org.apache.tez.runtime.task.TestTaskExecution.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.tez.runtime.task.TestTaskExecution.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.tez.runtime.task;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.ipc.ProtocolSignature;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ContainerId;
import org.apache.log4j.Logger;
import org.apache.tez.common.ContainerContext;
import org.apache.tez.common.ContainerTask;
import org.apache.tez.common.TezTaskUmbilicalProtocol;
import org.apache.tez.dag.api.ProcessorDescriptor;
import org.apache.tez.dag.api.TezConfiguration;
import org.apache.tez.dag.api.TezException;
import org.apache.tez.dag.api.UserPayload;
import org.apache.tez.dag.records.TezDAGID;
import org.apache.tez.dag.records.TezTaskAttemptID;
import org.apache.tez.dag.records.TezTaskID;
import org.apache.tez.dag.records.TezVertexID;
import org.apache.tez.runtime.api.AbstractLogicalIOProcessor;
import org.apache.tez.runtime.api.Event;
import org.apache.tez.runtime.api.LogicalInput;
import org.apache.tez.runtime.api.LogicalOutput;
import org.apache.tez.runtime.api.ProcessorContext;
import org.apache.tez.runtime.api.events.TaskAttemptCompletedEvent;
import org.apache.tez.runtime.api.events.TaskAttemptFailedEvent;
import org.apache.tez.runtime.api.impl.ExecutionContextImpl;
import org.apache.tez.runtime.api.impl.InputSpec;
import org.apache.tez.runtime.api.impl.OutputSpec;
import org.apache.tez.runtime.api.impl.TaskSpec;
import org.apache.tez.runtime.api.impl.TezEvent;
import org.apache.tez.runtime.api.impl.TezHeartbeatRequest;
import org.apache.tez.runtime.api.impl.TezHeartbeatResponse;
import org.apache.tez.runtime.common.resources.ScalingAllocator;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;

import com.google.common.collect.HashMultimap;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

// Tests in this class cannot be run in parallel.
public class TestTaskExecution {

    private static final Logger LOG = Logger.getLogger(TestTaskExecution.class);

    private static final String HEARTBEAT_EXCEPTION_STRING = "HeartbeatException";

    private static final Configuration defaultConf = new Configuration();
    private static final FileSystem localFs;
    private static final Path workDir;

    private static final ExecutorService taskExecutor = Executors.newFixedThreadPool(1);

    static {
        defaultConf.set("fs.defaultFS", "file:///");
        defaultConf.set(TezConfiguration.TEZ_TASK_SCALE_MEMORY_ALLOCATOR_CLASS, ScalingAllocator.class.getName());
        try {
            localFs = FileSystem.getLocal(defaultConf);
            Path wd = new Path(System.getProperty("test.build.data", "/tmp"),
                    TestTaskExecution.class.getSimpleName());
            workDir = localFs.makeQualified(wd);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Before
    public void reset() {
        TestProcessor.reset();
    }

    @AfterClass
    public static void shutdown() {
        taskExecutor.shutdownNow();
    }

    @Test(timeout = 5000)
    public void testSingleSuccessfulTask()
            throws IOException, InterruptedException, TezException, ExecutionException {
        ListeningExecutorService executor = null;
        try {
            ExecutorService rawExecutor = Executors.newFixedThreadPool(1);
            executor = MoreExecutors.listeningDecorator(rawExecutor);
            ApplicationId appId = ApplicationId.newInstance(10000, 1);
            TezTaskUmbilicalForTest umbilical = new TezTaskUmbilicalForTest();
            TaskReporter taskReporter = createTaskReporter(appId, umbilical);

            TezTaskRunner taskRunner = createTaskRunner(appId, umbilical, taskReporter, executor,
                    TestProcessor.CONF_EMPTY);
            // Setup the executor
            Future<Boolean> taskRunnerFuture = taskExecutor.submit(new TaskRunnerCallable(taskRunner));
            // Signal the processor to go through
            TestProcessor.signal();
            boolean result = taskRunnerFuture.get();
            assertTrue(result);
            assertNull(taskReporter.currentCallable);
            umbilical.verifyTaskSuccessEvent();
        } finally {
            executor.shutdownNow();
        }
    }

    @Test(timeout = 5000)
    public void testMultipleSuccessfulTasks()
            throws IOException, InterruptedException, TezException, ExecutionException {

        ListeningExecutorService executor = null;
        try {
            ExecutorService rawExecutor = Executors.newFixedThreadPool(1);
            executor = MoreExecutors.listeningDecorator(rawExecutor);
            ApplicationId appId = ApplicationId.newInstance(10000, 1);
            TezTaskUmbilicalForTest umbilical = new TezTaskUmbilicalForTest();
            TaskReporter taskReporter = createTaskReporter(appId, umbilical);

            TezTaskRunner taskRunner = createTaskRunner(appId, umbilical, taskReporter, executor,
                    TestProcessor.CONF_EMPTY);
            // Setup the executor
            Future<Boolean> taskRunnerFuture = taskExecutor.submit(new TaskRunnerCallable(taskRunner));
            // Signal the processor to go through
            TestProcessor.signal();
            boolean result = taskRunnerFuture.get();
            assertTrue(result);
            assertNull(taskReporter.currentCallable);
            umbilical.verifyTaskSuccessEvent();
            umbilical.resetTrackedEvents();

            taskRunner = createTaskRunner(appId, umbilical, taskReporter, executor, TestProcessor.CONF_EMPTY);
            // Setup the executor
            taskRunnerFuture = taskExecutor.submit(new TaskRunnerCallable(taskRunner));
            // Signal the processor to go through
            TestProcessor.signal();
            result = taskRunnerFuture.get();
            assertTrue(result);
            assertNull(taskReporter.currentCallable);
            umbilical.verifyTaskSuccessEvent();
        } finally {
            executor.shutdownNow();
        }
    }

    // test tasked failed due to exception in Processor
    @Test(timeout = 5000)
    public void testFailedTask() throws IOException, InterruptedException, TezException {

        ListeningExecutorService executor = null;
        try {
            ExecutorService rawExecutor = Executors.newFixedThreadPool(1);
            executor = MoreExecutors.listeningDecorator(rawExecutor);
            ApplicationId appId = ApplicationId.newInstance(10000, 1);
            TezTaskUmbilicalForTest umbilical = new TezTaskUmbilicalForTest();
            TaskReporter taskReporter = createTaskReporter(appId, umbilical);

            TezTaskRunner taskRunner = createTaskRunner(appId, umbilical, taskReporter, executor,
                    TestProcessor.CONF_THROW_TEZ_EXCEPTION);
            // Setup the executor
            Future<Boolean> taskRunnerFuture = taskExecutor.submit(new TaskRunnerCallable(taskRunner));
            // Signal the processor to go through
            TestProcessor.awaitStart();
            TestProcessor.signal();
            try {
                taskRunnerFuture.get();
                fail("Expecting the task to fail");
            } catch (ExecutionException e) {
                Throwable cause = e.getCause();
                LOG.info(cause.getClass().getName());
                assertTrue(cause instanceof TezException);
            }

            assertNull(taskReporter.currentCallable);
            umbilical.verifyTaskFailedEvent(
                    "Failure while running task:org.apache.tez.dag.api.TezException: TezException");
        } finally {
            executor.shutdownNow();
        }
    }

    // Test task failed due to Processor class not found
    @Test(timeout = 5000)
    public void testFailedTask2() throws IOException, InterruptedException, TezException {

        ListeningExecutorService executor = null;
        try {
            ExecutorService rawExecutor = Executors.newFixedThreadPool(1);
            executor = MoreExecutors.listeningDecorator(rawExecutor);
            ApplicationId appId = ApplicationId.newInstance(10000, 1);
            TezTaskUmbilicalForTest umbilical = new TezTaskUmbilicalForTest();
            TaskReporter taskReporter = createTaskReporter(appId, umbilical);

            TezTaskRunner taskRunner = createTaskRunner(appId, umbilical, taskReporter, executor,
                    "NotExitedProcessor", TestProcessor.CONF_THROW_TEZ_EXCEPTION);
            // Setup the executor
            Future<Boolean> taskRunnerFuture = taskExecutor.submit(new TaskRunnerCallable(taskRunner));
            try {
                taskRunnerFuture.get();
            } catch (ExecutionException e) {
                Throwable cause = e.getCause();
                LOG.info(cause.getClass().getName());
                assertTrue(cause instanceof TezException);
            }
            assertNull(taskReporter.currentCallable);
            umbilical.verifyTaskFailedEvent(
                    "Failure while running task:org.apache.tez.dag.api.TezUncheckedException: "
                            + "Unable to load class: NotExitedProcessor");
        } finally {
            executor.shutdownNow();
        }
    }

    @Test(timeout = 5000)
    public void testHeartbeatException() throws IOException, InterruptedException, TezException {

        ListeningExecutorService executor = null;
        try {
            ExecutorService rawExecutor = Executors.newFixedThreadPool(1);
            executor = MoreExecutors.listeningDecorator(rawExecutor);
            ApplicationId appId = ApplicationId.newInstance(10000, 1);
            TezTaskUmbilicalForTest umbilical = new TezTaskUmbilicalForTest();
            TaskReporter taskReporter = createTaskReporter(appId, umbilical);

            TezTaskRunner taskRunner = createTaskRunner(appId, umbilical, taskReporter, executor,
                    TestProcessor.CONF_EMPTY);
            // Setup the executor
            Future<Boolean> taskRunnerFuture = taskExecutor.submit(new TaskRunnerCallable(taskRunner));
            // Signal the processor to go through
            TestProcessor.awaitStart();
            umbilical.signalThrowException();
            umbilical.awaitRegisteredEvent();
            // Not signaling an actual start to verify task interruption
            try {
                taskRunnerFuture.get();
                fail("Expecting the task to fail");
            } catch (ExecutionException e) {
                Throwable cause = e.getCause();
                assertTrue(cause instanceof IOException);
                assertTrue(cause.getMessage().contains(HEARTBEAT_EXCEPTION_STRING));
            }
            TestProcessor.awaitCompletion();
            assertTrue(TestProcessor.wasInterrupted());
            assertNull(taskReporter.currentCallable);
            // No completion events since umbilical communication already failed.
            umbilical.verifyNoCompletionEvents();
        } finally {
            executor.shutdownNow();
        }
    }

    @Test(timeout = 5000)
    public void testHeartbeatShouldDie()
            throws IOException, InterruptedException, TezException, ExecutionException {

        ListeningExecutorService executor = null;
        try {
            ExecutorService rawExecutor = Executors.newFixedThreadPool(1);
            executor = MoreExecutors.listeningDecorator(rawExecutor);
            ApplicationId appId = ApplicationId.newInstance(10000, 1);
            TezTaskUmbilicalForTest umbilical = new TezTaskUmbilicalForTest();
            TaskReporter taskReporter = createTaskReporter(appId, umbilical);

            TezTaskRunner taskRunner = createTaskRunner(appId, umbilical, taskReporter, executor,
                    TestProcessor.CONF_EMPTY);
            // Setup the executor
            Future<Boolean> taskRunnerFuture = taskExecutor.submit(new TaskRunnerCallable(taskRunner));
            // Signal the processor to go through
            TestProcessor.awaitStart();
            umbilical.signalSendShouldDie();
            umbilical.awaitRegisteredEvent();
            // Not signaling an actual start to verify task interruption

            boolean result = taskRunnerFuture.get();
            assertFalse(result);

            TestProcessor.awaitCompletion();
            assertTrue(TestProcessor.wasInterrupted());
            assertNull(taskReporter.currentCallable);
            // TODO Is this statement correct ?
            // No completion events since shouldDie was requested by the AM, which should have killed the
            // task.
            umbilical.verifyNoCompletionEvents();
        } finally {
            executor.shutdownNow();
        }
    }

    @Test(timeout = 5000)
    public void testGetTaskShouldDie() throws InterruptedException, ExecutionException {
        ListeningExecutorService executor = null;
        try {
            ExecutorService rawExecutor = Executors.newFixedThreadPool(1);
            executor = MoreExecutors.listeningDecorator(rawExecutor);
            ApplicationId appId = ApplicationId.newInstance(10000, 1);
            ApplicationAttemptId appAttemptId = ApplicationAttemptId.newInstance(appId, 1);
            ContainerId containerId = ContainerId.newInstance(appAttemptId, 1);

            TezTaskUmbilicalForTest umbilical = new TezTaskUmbilicalForTest();
            ContainerContext containerContext = new ContainerContext(containerId.toString());

            ContainerReporter containerReporter = new ContainerReporter(umbilical, containerContext, 100);
            ListenableFuture<ContainerTask> getTaskFuture = executor.submit(containerReporter);

            getTaskFuture.get();
            assertEquals(1, umbilical.getTaskInvocations);

        } finally {
            executor.shutdownNow();
        }
    }

    // Potential new tests
    // Different states - initialization failure, close failure
    // getTask states

    private static class TaskRunnerCallable implements Callable<Boolean> {
        private final TezTaskRunner taskRunner;

        public TaskRunnerCallable(TezTaskRunner taskRunner) {
            this.taskRunner = taskRunner;
        }

        @Override
        public Boolean call() throws Exception {
            return taskRunner.run();
        }
    }

    // Uses static fields for signaling. Ensure only used by one test at a time.
    public static class TestProcessor extends AbstractLogicalIOProcessor {

        public static final byte[] CONF_EMPTY = new byte[] { 0 };
        public static final byte[] CONF_THROW_IO_EXCEPTION = new byte[] { 1 };
        public static final byte[] CONF_THROW_TEZ_EXCEPTION = new byte[] { 2 };
        public static final byte[] CONF_SIGNAL_FATAL_AND_THROW = new byte[] { 4 };
        public static final byte[] CONF_SIGNAL_FATAL_AND_LOOP = new byte[] { 8 };
        public static final byte[] CONF_SIGNAL_FATAL_AND_COMPLETE = new byte[] { 16 };

        private static final Logger LOG = Logger.getLogger(TestProcessor.class);

        private static final ReentrantLock processorLock = new ReentrantLock();
        private static final Condition processorCondition = processorLock.newCondition();
        private static final Condition completionCondition = processorLock.newCondition();
        private static final Condition runningCondition = processorLock.newCondition();
        private static boolean completed = false;
        private static boolean running = false;
        private static boolean signalled = false;

        public static boolean receivedInterrupt = false;

        private boolean throwIOException = false;
        private boolean throwTezException = false;
        private boolean signalFatalAndThrow = false;
        private boolean signalFatalAndLoop = false;
        private boolean signalFatalAndComplete = false;

        public TestProcessor(ProcessorContext context) {
            super(context);
        }

        @Override
        public void initialize() throws Exception {
            parseConf(getContext().getUserPayload().deepCopyAsArray());
        }

        @Override
        public void handleEvents(List<Event> processorEvents) {

        }

        @Override
        public void close() throws Exception {

        }

        private void parseConf(byte[] bytes) {
            byte b = bytes[0];
            throwIOException = (b & 1) > 1;
            throwTezException = (b & 2) > 1;
            signalFatalAndThrow = (b & 4) > 1;
            signalFatalAndLoop = (b & 8) > 1;
            signalFatalAndComplete = (b & 16) > 1;
        }

        public static void reset() {
            signalled = false;
            receivedInterrupt = false;
            completed = false;
            running = false;
        }

        public static void signal() {
            LOG.info("Signalled");
            processorLock.lock();
            try {
                signalled = true;
                processorCondition.signal();
            } finally {
                processorLock.unlock();
            }
        }

        public static void awaitStart() throws InterruptedException {
            LOG.info("Awaiting Process run");
            processorLock.lock();
            try {
                if (running) {
                    return;
                }
                runningCondition.await();
            } finally {
                processorLock.unlock();
            }
        }

        public static void awaitCompletion() throws InterruptedException {
            LOG.info("Await completion");
            processorLock.lock();
            try {
                if (completed) {
                    return;
                } else {
                    completionCondition.await();
                }
            } finally {
                processorLock.unlock();
            }
        }

        public static boolean wasInterrupted() {
            processorLock.lock();
            try {
                return receivedInterrupt;
            } finally {
                processorLock.unlock();
            }
        }

        @Override
        public void run(Map<String, LogicalInput> inputs, Map<String, LogicalOutput> outputs) throws Exception {
            processorLock.lock();
            running = true;
            runningCondition.signal();
            try {
                try {
                    LOG.info("Signal is: " + signalled);
                    if (!signalled) {
                        LOG.info("Waiting for processor signal");
                        processorCondition.await();
                    }
                    if (Thread.currentThread().isInterrupted()) {
                        throw new InterruptedException();
                    }
                    LOG.info("Received processor signal");
                    if (throwIOException) {
                        throw new IOException();
                    } else if (throwTezException) {
                        throw new TezException("TezException");
                    } else if (signalFatalAndThrow) {
                        IOException io = new IOException("FATALERROR");
                        getContext().fatalError(io, "FATALERROR");
                        throw io;
                    } else if (signalFatalAndComplete) {
                        IOException io = new IOException("FATALERROR");
                        getContext().fatalError(io, "FATALERROR");
                        return;
                    } else if (signalFatalAndLoop) {
                        IOException io = new IOException("FATALERROR");
                        getContext().fatalError(io, "FATALERROR");
                        LOG.info("Waiting for Processor signal again");
                        processorCondition.await();
                        LOG.info("Received second processor signal");
                    }
                } catch (InterruptedException e) {
                    receivedInterrupt = true;
                }
            } finally {
                completed = true;
                completionCondition.signal();
                processorLock.unlock();
            }
        }
    }

    private static class TezTaskUmbilicalForTest implements TezTaskUmbilicalProtocol {

        private static final Logger LOG = Logger.getLogger(TezTaskUmbilicalForTest.class);

        private final List<TezEvent> requestEvents = new LinkedList<TezEvent>();

        private final ReentrantLock umbilicalLock = new ReentrantLock();
        private final Condition eventCondition = umbilicalLock.newCondition();
        private boolean pendingEvent = false;
        private boolean eventEnacted = false;

        volatile int getTaskInvocations = 0;

        private boolean shouldThrowException = false;
        private boolean shouldSendDieSignal = false;

        public void signalThrowException() {
            umbilicalLock.lock();
            try {
                shouldThrowException = true;
                pendingEvent = true;
            } finally {
                umbilicalLock.unlock();
            }
        }

        public void signalSendShouldDie() {
            umbilicalLock.lock();
            try {
                shouldSendDieSignal = true;
                pendingEvent = true;
            } finally {
                umbilicalLock.unlock();
            }
        }

        public void awaitRegisteredEvent() throws InterruptedException {
            umbilicalLock.lock();
            try {
                if (eventEnacted) {
                    return;
                }
                LOG.info("Awaiting event");
                eventCondition.await();
            } finally {
                umbilicalLock.unlock();
            }
        }

        public void resetTrackedEvents() {
            umbilicalLock.lock();
            try {
                requestEvents.clear();
            } finally {
                umbilicalLock.unlock();
            }
        }

        public void verifyNoCompletionEvents() {
            umbilicalLock.lock();
            try {
                for (TezEvent event : requestEvents) {
                    if (event.getEvent() instanceof TaskAttemptFailedEvent) {
                        fail("Found a TaskAttemptFailedEvent when not expected");
                    }
                    if (event.getEvent() instanceof TaskAttemptCompletedEvent) {
                        fail("Found a TaskAttemptCompletedvent when not expected");
                    }
                }
            } finally {
                umbilicalLock.unlock();
            }
        }

        public void verifyTaskFailedEvent(String diagnostics) {
            umbilicalLock.lock();
            try {
                for (TezEvent event : requestEvents) {
                    if (event.getEvent() instanceof TaskAttemptFailedEvent) {
                        TaskAttemptFailedEvent failedEvent = (TaskAttemptFailedEvent) event.getEvent();
                        if (failedEvent.getDiagnostics().startsWith(diagnostics)) {
                            return;
                        } else {
                            fail("No detailed diagnostics message in TaskAttemptFailedEvent");
                        }
                    }
                }
                fail("No TaskAttemptFailedEvents sent over umbilical");
            } finally {
                umbilicalLock.unlock();
            }
        }

        public void verifyTaskSuccessEvent() {
            umbilicalLock.lock();
            try {
                for (TezEvent event : requestEvents) {
                    if (event.getEvent() instanceof TaskAttemptCompletedEvent) {
                        return;
                    }
                }
                fail("No TaskAttemptFailedEvents sent over umbilical");
            } finally {
                umbilicalLock.unlock();
            }
        }

        @Override
        public long getProtocolVersion(String protocol, long clientVersion) throws IOException {
            return 0;
        }

        @Override
        public ProtocolSignature getProtocolSignature(String protocol, long clientVersion, int clientMethodsHash)
                throws IOException {
            return null;
        }

        @Override
        public ContainerTask getTask(ContainerContext containerContext) throws IOException {
            // Return shouldDie = true
            getTaskInvocations++;
            return new ContainerTask(null, true, null, null, false);
        }

        @Override
        public boolean canCommit(TezTaskAttemptID taskid) throws IOException {
            return true;
        }

        @Override
        public TezHeartbeatResponse heartbeat(TezHeartbeatRequest request) throws IOException, TezException {
            umbilicalLock.lock();
            if (request.getEvents() != null) {
                requestEvents.addAll(request.getEvents());
            }
            try {
                if (shouldThrowException) {
                    LOG.info("TestUmbilical throwing Exception");
                    throw new IOException(HEARTBEAT_EXCEPTION_STRING);
                }
                TezHeartbeatResponse response = new TezHeartbeatResponse();
                response.setLastRequestId(request.getRequestId());
                if (shouldSendDieSignal) {
                    LOG.info("TestUmbilical returning shouldDie=true");
                    response.setShouldDie();
                }
                return response;
            } finally {
                if (pendingEvent) {
                    eventEnacted = true;
                    LOG.info("Signalling Event");
                    eventCondition.signal();
                }
                umbilicalLock.unlock();
            }
        }
    }

    private TaskReporter createTaskReporter(ApplicationId appId, TezTaskUmbilicalForTest umbilical) {
        TaskReporter taskReporter = new TaskReporter(umbilical, 100, 1000, 100, new AtomicLong(0),
                createContainerId(appId).toString());
        return taskReporter;
    }

    private TezTaskRunner createTaskRunner(ApplicationId appId, TezTaskUmbilicalForTest umbilical,
            TaskReporter taskReporter, ListeningExecutorService executor, byte[] processorConf) throws IOException {
        return createTaskRunner(appId, umbilical, taskReporter, executor, TestProcessor.class.getName(),
                processorConf);
    }

    private TezTaskRunner createTaskRunner(ApplicationId appId, TezTaskUmbilicalForTest umbilical,
            TaskReporter taskReporter, ListeningExecutorService executor, String processorClass,
            byte[] processorConf) throws IOException {
        TezConfiguration tezConf = new TezConfiguration(defaultConf);
        UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
        Path testDir = new Path(workDir, UUID.randomUUID().toString());
        String[] localDirs = new String[] { testDir.toString() };

        TezDAGID dagId = TezDAGID.getInstance(appId, 1);
        TezVertexID vertexId = TezVertexID.getInstance(dagId, 1);
        TezTaskID taskId = TezTaskID.getInstance(vertexId, 1);
        TezTaskAttemptID taskAttemptId = TezTaskAttemptID.getInstance(taskId, 1);
        ProcessorDescriptor processorDescriptor = ProcessorDescriptor.create(processorClass)
                .setUserPayload(UserPayload.create(ByteBuffer.wrap(processorConf)));
        TaskSpec taskSpec = new TaskSpec(taskAttemptId, "dagName", "vertexName", -1, processorDescriptor,
                new ArrayList<InputSpec>(), new ArrayList<OutputSpec>(), null);

        TezTaskRunner taskRunner = new TezTaskRunner(tezConf, ugi, localDirs, taskSpec, umbilical, 1,
                new HashMap<String, ByteBuffer>(), new HashMap<String, String>(),
                HashMultimap.<String, String>create(), taskReporter, executor, null, "",
                new ExecutionContextImpl("localhost"), Runtime.getRuntime().maxMemory());
        return taskRunner;
    }

    private ContainerId createContainerId(ApplicationId appId) {
        ApplicationAttemptId appAttemptId = ApplicationAttemptId.newInstance(appId, 1);
        ContainerId containerId = ContainerId.newInstance(appAttemptId, 1);
        return containerId;
    }
}