org.apache.hadoop.yarn.server.nodemanager.containermanager.TestContainerManager.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.yarn.server.nodemanager.containermanager.TestContainerManager.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.hadoop.yarn.server.nodemanager.containermanager;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.FileContext;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.UnsupportedFileSystemException;
import org.apache.hadoop.io.DataOutputBuffer;
import org.apache.hadoop.security.Credentials;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.ssl.JWTSecurityMaterial;
import org.apache.hadoop.security.ssl.X509SecurityMaterial;
import org.apache.hadoop.service.Service;
import org.apache.hadoop.util.Shell;
import org.apache.hadoop.yarn.api.protocolrecords.IncreaseContainersResourceRequest;
import org.apache.hadoop.yarn.api.protocolrecords.IncreaseContainersResourceResponse;
import org.apache.hadoop.yarn.api.protocolrecords.GetContainerStatusesRequest;
import org.apache.hadoop.yarn.api.protocolrecords.GetContainerStatusesResponse;
import org.apache.hadoop.yarn.api.protocolrecords.SignalContainerRequest;
import org.apache.hadoop.yarn.api.protocolrecords.StartContainerRequest;
import org.apache.hadoop.yarn.api.protocolrecords.StartContainersRequest;
import org.apache.hadoop.yarn.api.protocolrecords.StartContainersResponse;
import org.apache.hadoop.yarn.api.protocolrecords.StopContainersRequest;
import org.apache.hadoop.yarn.api.protocolrecords.StopContainersResponse;
import org.apache.hadoop.yarn.api.protocolrecords.impl.pb.GetContainerStatusesRequestPBImpl;
import org.apache.hadoop.yarn.api.protocolrecords.impl.pb.StartContainersRequestPBImpl;
import org.apache.hadoop.yarn.api.protocolrecords.impl.pb.StopContainersRequestPBImpl;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ContainerExitStatus;
import org.apache.hadoop.yarn.api.records.ContainerId;
import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;
import org.apache.hadoop.yarn.api.records.ContainerState;
import org.apache.hadoop.yarn.api.records.ContainerStatus;
import org.apache.hadoop.yarn.api.records.LocalResource;
import org.apache.hadoop.yarn.api.records.LocalResourceType;
import org.apache.hadoop.yarn.api.records.LocalResourceVisibility;
import org.apache.hadoop.yarn.api.records.LogAggregationContext;
import org.apache.hadoop.yarn.api.records.NodeId;
import org.apache.hadoop.yarn.api.records.Priority;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.SerializedException;
import org.apache.hadoop.yarn.api.records.SignalContainerCommand;
import org.apache.hadoop.yarn.api.records.Token;
import org.apache.hadoop.yarn.api.records.URL;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.InvalidContainerException;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.security.ContainerTokenIdentifier;
import org.apache.hadoop.yarn.security.NMTokenIdentifier;
import org.apache.hadoop.yarn.server.api.ResourceManagerConstants;
import org.apache.hadoop.yarn.server.nodemanager.CMgrCompletedAppsEvent;
import org.apache.hadoop.yarn.server.nodemanager.CMgrDecreaseContainersResourceEvent;
import org.apache.hadoop.yarn.server.nodemanager.CMgrSignalContainersEvent;
import org.apache.hadoop.yarn.server.nodemanager.CMgrUpdateJWTEvent;
import org.apache.hadoop.yarn.server.nodemanager.CMgrUpdateX509Event;
import org.apache.hadoop.yarn.server.nodemanager.ContainerExecutor.Signal;
import org.apache.hadoop.yarn.server.nodemanager.Context;
import org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor;
import org.apache.hadoop.yarn.server.nodemanager.DeletionService;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.TestAuxServices.ServiceA;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.application.ApplicationState;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerImpl;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.ContainerLocalizer;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.ResourceLocalizationService;
import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerSignalContext;
import org.apache.hadoop.yarn.server.nodemanager.recovery.NMMemoryStateStoreService;
import org.apache.hadoop.yarn.server.nodemanager.recovery.NMStateStoreService;
import org.apache.hadoop.yarn.server.nodemanager.security.NMContainerTokenSecretManager;
import org.apache.hadoop.yarn.server.utils.BuilderUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;

public class TestContainerManager extends BaseContainerManagerTest {

    public TestContainerManager() throws UnsupportedFileSystemException {
        super();
    }

    static {
        LOG = LogFactory.getLog(TestContainerManager.class);
    }

    @Override
    @Before
    public void setup() throws IOException {
        super.setup();
    }

    public static ContainerId createContainerId(int id) {
        ApplicationId appId = ApplicationId.newInstance(0, 0);
        ApplicationAttemptId appAttemptId = ApplicationAttemptId.newInstance(appId, 1);
        ContainerId containerId = ContainerId.newContainerId(appAttemptId, id);
        return containerId;
    }

    @Override
    protected ContainerManagerImpl createContainerManager(DeletionService delSrvc) {
        return new ContainerManagerImpl(context, exec, delSrvc, nodeStatusUpdater, metrics, dirsHandler) {
            @Override
            public void setBlockNewContainerRequests(boolean blockNewContainerRequests) {
                // do nothing
            }

            @Override
            protected UserGroupInformation getRemoteUgi() throws YarnException {
                ApplicationId appId = ApplicationId.newInstance(0, 0);
                ApplicationAttemptId appAttemptId = ApplicationAttemptId.newInstance(appId, 1);
                UserGroupInformation ugi = UserGroupInformation.createRemoteUser(appAttemptId.toString());
                ugi.addTokenIdentifier(new NMTokenIdentifier(appAttemptId, context.getNodeId(), user,
                        context.getNMTokenSecretManager().getCurrentKey().getKeyId()));
                return ugi;
            }
        };
    }

    @Test
    public void testContainerManagerInitialization() throws IOException {

        containerManager.start();

        InetAddress localAddr = InetAddress.getLocalHost();
        String fqdn = localAddr.getCanonicalHostName();
        if (!localAddr.getHostAddress().equals(fqdn)) {
            // only check if fqdn is not same as ip
            // api returns ip in case of resolution failure
            Assert.assertEquals(fqdn, context.getNodeId().getHost());
        }

        // Just do a query for a non-existing container.
        boolean throwsException = false;
        try {
            List<ContainerId> containerIds = new ArrayList<ContainerId>();
            ContainerId id = createContainerId(0);
            containerIds.add(id);
            GetContainerStatusesRequest request = GetContainerStatusesRequest.newInstance(containerIds);
            GetContainerStatusesResponse response = containerManager.getContainerStatuses(request);
            if (response.getFailedRequests().containsKey(id)) {
                throw response.getFailedRequests().get(id).deSerialize();
            }
        } catch (Throwable e) {
            throwsException = true;
        }
        Assert.assertTrue(throwsException);
    }

    private LocalResource createLocalResource(File file) {
        return createLocalResource(file, LocalResourceVisibility.PRIVATE, LocalResourceType.FILE);
    }

    private LocalResource createLocalResource(File file, LocalResourceVisibility visibility,
            LocalResourceType type) {
        URL url = URL.fromPath(localFS.makeQualified(new Path(file.getAbsolutePath())));
        LocalResource lr = recordFactory.newRecordInstance(LocalResource.class);
        lr.setResource(url);
        lr.setSize(file.length());
        lr.setVisibility(visibility);
        lr.setType(type);
        lr.setTimestamp(file.lastModified());
        return lr;
    }

    @Test
    public void testSecurityMaterialContainerUpdate() throws Exception {
        String keystoresContent0 = "keystore_content0";
        String keystoresPassword0 = "password0";
        String jwt0 = "jwt0";

        String keystoresContent1 = "keystore_content1";
        String keystoresPassword1 = "password1";
        String jwt1 = "jwt1";
        conf.setBoolean(YarnConfiguration.NM_RECOVERY_ENABLED, false);
        NMStateStoreService stateStore = new NMMemoryStateStoreService();
        stateStore.init(conf);
        stateStore.start();
        Context context = createContext(conf, stateStore, true, true);
        final ContainerManagerImpl cm = createContainerManager(delSrvc, context);
        cm.init(conf);
        cm.start();

        // Create run script
        File scriptFile = Shell.appendScriptExtension(tmpDir, "script");
        FileWriter fw = new FileWriter(scriptFile, false);

        if (Shell.WINDOWS) {
            fw.write("@ping -n 20 127.0.0.1 >nul");
        } else {
            fw.write("\numask 0");
            fw.write("\nexec sleep 15");
        }
        fw.close();

        ContainerLaunchContext ctx0 = createContainerLaunchContext(scriptFile);

        final ContainerId cid0 = createContainerId(0);
        UserGroupInformation user = UserGroupInformation
                .createRemoteUser(cid0.getApplicationAttemptId().toString());
        StartContainerRequest scr0 = StartContainerRequest.newInstance(ctx0,
                createContainerToken(cid0, 0, context.getNodeId(), user.getShortUserName(),
                        context.getContainerTokenSecretManager(), userFolder));

        ContainerLaunchContext ctx1 = createContainerLaunchContext(scriptFile);
        final ContainerId cid1 = createContainerId(1);
        StartContainerRequest scr1 = StartContainerRequest.newInstance(ctx1,
                createContainerToken(cid1, 0, context.getNodeId(), user.getShortUserName(),
                        context.getContainerTokenSecretManager(), userFolder));

        List<StartContainerRequest> scrList = new ArrayList<>(2);
        scrList.add(scr0);
        scrList.add(scr1);

        StartContainersRequest allRequests = StartContainersRequest.newInstance(scrList);
        allRequests.setKeyStore(ByteBuffer.wrap(keystoresContent0.getBytes()));
        allRequests.setKeyStorePassword(keystoresPassword0);
        allRequests.setTrustStore(ByteBuffer.wrap(keystoresContent0.getBytes()));
        allRequests.setTrustStorePassword(keystoresPassword0);
        allRequests.setJWT(jwt0);

        startContainers(context, cm, cid0.getApplicationAttemptId(), allRequests, user);

        BaseContainerManagerTest.waitForContainerState(cm, cid0, ContainerState.RUNNING);
        BaseContainerManagerTest.waitForContainerState(cm, cid1, ContainerState.RUNNING);

        ContainerImpl container0 = (ContainerImpl) cm.getContext().getContainers().get(cid0);
        waitForContainerToRunningState(container0);

        ContainerImpl container1 = (ContainerImpl) cm.getContext().getContainers().get(cid1);
        waitForContainerToRunningState(container1);

        ApplicationId appId = container0.getContainerId().getApplicationAttemptId().getApplicationId();
        X509SecurityMaterial x509 = context.getCertificateLocalizationService()
                .getX509MaterialLocation(user.getShortUserName(), appId.toString());
        assertNotNull(x509);
        assertEquals(keystoresPassword0, x509.getKeyStorePass());
        JWTSecurityMaterial jwt = context.getCertificateLocalizationService()
                .getJWTMaterialLocation(user.getShortUserName(), appId.toString());
        assertNotNull(jwt);
        assertEquals(jwt0, jwt.getToken());

        File[] container0SecurityMaterial = assertSecurityFilesExist(container0);
        File[] container1SecurityMaterial = assertSecurityFilesExist(container1);

        // Keystore
        assertSecurityMaterial(container0SecurityMaterial[0], ByteBuffer.wrap(keystoresContent0.getBytes()), true);
        // Truststore
        assertSecurityMaterial(container0SecurityMaterial[1], ByteBuffer.wrap(keystoresContent0.getBytes()), true);
        // Keyphrase
        assertSecurityMaterial(container0SecurityMaterial[2], keystoresPassword0, true);
        // JWT
        assertSecurityMaterial(container0SecurityMaterial[3], jwt0, true);

        assertSecurityMaterial(container1SecurityMaterial[0], ByteBuffer.wrap(keystoresContent0.getBytes()), true);
        assertSecurityMaterial(container1SecurityMaterial[1], ByteBuffer.wrap(keystoresContent0.getBytes()), true);
        assertSecurityMaterial(container1SecurityMaterial[2], keystoresPassword0, true);
        assertSecurityMaterial(container1SecurityMaterial[3], jwt0, true);

        // Events to update X.509 for containers
        CMgrUpdateX509Event x509UpdateC0 = new CMgrUpdateX509Event(cid0,
                ByteBuffer.wrap(keystoresContent1.getBytes()), keystoresPassword1.toCharArray(),
                ByteBuffer.wrap(keystoresContent1.getBytes()), keystoresPassword1.toCharArray(), 1);
        CMgrUpdateX509Event x509UpdateC1 = new CMgrUpdateX509Event(cid1,
                ByteBuffer.wrap(keystoresContent1.getBytes()), keystoresPassword1.toCharArray(),
                ByteBuffer.wrap(keystoresContent1.getBytes()), keystoresPassword1.toCharArray(), 1);

        // Events to update JWT for containers
        CMgrUpdateJWTEvent jwtUpdateC0 = new CMgrUpdateJWTEvent(cid0, jwt1, System.currentTimeMillis());
        CMgrUpdateJWTEvent jwtUpdateC1 = new CMgrUpdateJWTEvent(cid1, jwt1, System.currentTimeMillis());

        cm.handle(x509UpdateC0);
        cm.handle(x509UpdateC1);
        cm.handle(jwtUpdateC0);
        cm.handle(jwtUpdateC1);

        waitForSecurityMaterialUpdatersToFinish(cid0, cm);
        waitForSecurityMaterialUpdatersToFinish(cid1, cm);

        assertSecurityMaterial(container0SecurityMaterial[0], ByteBuffer.wrap(keystoresContent1.getBytes()), true);
        assertSecurityMaterial(container0SecurityMaterial[1], ByteBuffer.wrap(keystoresContent1.getBytes()), true);
        assertSecurityMaterial(container0SecurityMaterial[2], keystoresPassword1, true);
        assertSecurityMaterial(container0SecurityMaterial[3], jwt1, true);

        assertSecurityMaterial(container1SecurityMaterial[0], ByteBuffer.wrap(keystoresContent1.getBytes()), true);
        assertSecurityMaterial(container1SecurityMaterial[1], ByteBuffer.wrap(keystoresContent1.getBytes()), true);
        assertSecurityMaterial(container1SecurityMaterial[2], keystoresPassword1, true);
        assertSecurityMaterial(container1SecurityMaterial[3], jwt1, true);

        cm.stop();
    }

    private StartContainersResponse startContainers(final Context context, final ContainerManagerImpl cm,
            ApplicationAttemptId attemptId, final StartContainersRequest scr, UserGroupInformation user)
            throws Exception {

        NMTokenIdentifier nmToken = new NMTokenIdentifier(attemptId, context.getNodeId(), user.getShortUserName(),
                context.getNMTokenSecretManager().getCurrentKey().getKeyId());
        user.addTokenIdentifier(nmToken);
        return user.doAs(new PrivilegedExceptionAction<StartContainersResponse>() {
            @Override
            public StartContainersResponse run() throws Exception {
                return cm.startContainers(scr);
            }
        });
    }

    private void waitForSecurityMaterialUpdatersToFinish(ContainerId cid, ContainerManagerImpl cm)
            throws InterruptedException {
        int numOfRetries = 0;
        while (cm.getX509Updaters().containsKey(cid) && numOfRetries < 10) {
            Thread.sleep(1000);
            numOfRetries++;
        }

        numOfRetries = 0;
        while (cm.getJWTUpdaters().containsKey(cid) && numOfRetries < 10) {
            Thread.sleep(1000);
            numOfRetries++;
        }
    }

    private ContainerLaunchContext createContainerLaunchContext(File runScript) throws IOException {
        Map<String, LocalResource> lrs = new HashMap<>(1);
        lrs.put("script",
                createLocalResource(runScript, LocalResourceVisibility.APPLICATION, LocalResourceType.FILE));

        Credentials containerCreds = new Credentials();
        DataOutputBuffer dob = new DataOutputBuffer();
        containerCreds.writeTokenStorageToStream(dob);
        ByteBuffer containerTokens = ByteBuffer.wrap(dob.getData(), 0, dob.getLength());
        ContainerLaunchContext ctx = recordFactory.newRecordInstance(ContainerLaunchContext.class);
        ctx.setLocalResources(lrs);
        List<String> commands = Arrays.asList(Shell.getRunScriptCommand(runScript));
        ctx.setCommands(commands);
        ctx.setTokens(containerTokens);
        return ctx;
    }

    private void writeByteBufferToFile(File target, ByteBuffer data) throws IOException {
        FileChannel fileChannel = new FileOutputStream(target, false).getChannel();
        fileChannel.write(data);
        fileChannel.close();
    }

    private void waitForContainerToRunningState(ContainerImpl container) throws InterruptedException {
        int numOfRetries = 0;
        while (!container.getContainerState()
                .equals(org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerState.RUNNING)
                && numOfRetries < 10) {
            Thread.sleep(300);
            numOfRetries++;
        }
        assertEquals(org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerState.RUNNING,
                container.getContainerState());
    }

    private File[] assertSecurityFilesExist(ContainerImpl container) {
        container.identifyCryptoMaterialLocation();
        File[] cryptoMaterial = new File[4];
        cryptoMaterial[0] = container.getKeyStoreLocalizedPath();
        cryptoMaterial[1] = container.getTrustStoreLocalizedPath();
        cryptoMaterial[2] = container.getPasswordFileLocalizedPath();
        cryptoMaterial[3] = container.getJWTLocalizedPath();

        for (int i = 0; i < cryptoMaterial.length; i++) {
            assertTrue(cryptoMaterial[i].exists());
        }
        return cryptoMaterial;
    }

    private void assertSecurityMaterial(File materialFile, ByteBuffer expected, boolean assertEquals)
            throws IOException {
        ByteBuffer fromFile = readFileToByteBuffer(materialFile);
        if (assertEquals) {
            assertTrue(expected.equals(fromFile));
        } else {
            assertFalse(expected.equals(fromFile));
        }
    }

    private void assertSecurityMaterial(File materialFile, String expected, boolean assertEquals)
            throws IOException {
        String fromFile = FileUtils.readFileToString(materialFile);
        if (assertEquals) {
            assertEquals(expected, fromFile);
        } else {
            assertNotEquals(expected, fromFile);
        }
    }

    private void assertUpdatedCryptoMaterial(File[] cryptoMaterialFiles, ByteBuffer oldKeyStore,
            ByteBuffer newKeyStore, ByteBuffer oldTrustStore, ByteBuffer newTrustStore, String oldPassword,
            String newPassword) throws IOException {
        ByteBuffer newKeyStoreBB = readFileToByteBuffer(cryptoMaterialFiles[0]);
        assertFalse(oldKeyStore.equals(newKeyStoreBB));
        assertTrue(newKeyStore.equals(newKeyStoreBB));

        ByteBuffer newTrustStoreBB = readFileToByteBuffer(cryptoMaterialFiles[1]);
        assertFalse(oldTrustStore.equals(newTrustStoreBB));
        assertTrue(newTrustStore.equals(newTrustStoreBB));

        String newPasswordU = FileUtils.readFileToString(cryptoMaterialFiles[2]);
        assertNotEquals(oldPassword, newPasswordU);
        assertEquals(newPassword, newPasswordU);
    }

    private ByteBuffer readFileToByteBuffer(File source) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(128);
        FileChannel fileChannel = new FileInputStream(source).getChannel();
        fileChannel.read(buffer);
        fileChannel.close();
        buffer.flip();
        return buffer;
    }

    @Test
    public void testContainerSetup() throws Exception {

        containerManager.start();

        // ////// Create the resources for the container
        File dir = new File(tmpDir, "dir");
        dir.mkdirs();
        File file = new File(dir, "file");
        PrintWriter fileWriter = new PrintWriter(file);
        fileWriter.write("Hello World!");
        fileWriter.close();

        // ////// Construct the Container-id
        ContainerId cId = createContainerId(0);

        // ////// Construct the container-spec.
        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);
        URL resource_alpha = URL.fromPath(localFS.makeQualified(new Path(file.getAbsolutePath())));
        LocalResource rsrc_alpha = recordFactory.newRecordInstance(LocalResource.class);
        rsrc_alpha.setResource(resource_alpha);
        rsrc_alpha.setSize(-1);
        rsrc_alpha.setVisibility(LocalResourceVisibility.APPLICATION);
        rsrc_alpha.setType(LocalResourceType.FILE);
        rsrc_alpha.setTimestamp(file.lastModified());
        String destinationFile = "dest_file";
        Map<String, LocalResource> localResources = new HashMap<String, LocalResource>();
        localResources.put(destinationFile, rsrc_alpha);
        containerLaunchContext.setLocalResources(localResources);

        StartContainerRequest scRequest = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                        context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list = new ArrayList<StartContainerRequest>();
        list.add(scRequest);
        StartContainersRequest allRequests = StartContainersRequest.newInstance(list);
        containerManager.startContainers(allRequests);

        BaseContainerManagerTest.waitForContainerState(containerManager, cId, ContainerState.COMPLETE);

        // Now ascertain that the resources are localised correctly.
        ApplicationId appId = cId.getApplicationAttemptId().getApplicationId();
        String appIDStr = appId.toString();
        String containerIDStr = cId.toString();
        File userCacheDir = new File(localDir, ContainerLocalizer.USERCACHE);
        File userDir = new File(userCacheDir, userFolder);
        File appCache = new File(userDir, ContainerLocalizer.APPCACHE);
        File appDir = new File(appCache, appIDStr);
        File containerDir = new File(appDir, containerIDStr);
        File targetFile = new File(containerDir, destinationFile);
        File sysDir = new File(localDir, ResourceLocalizationService.NM_PRIVATE_DIR);
        File appSysDir = new File(sysDir, appIDStr);
        File containerSysDir = new File(appSysDir, containerIDStr);

        for (File f : new File[] { localDir, sysDir, userCacheDir, appDir, appSysDir, containerDir,
                containerSysDir }) {
            Assert.assertTrue(f.getAbsolutePath() + " doesn't exist!!", f.exists());
            Assert.assertTrue(f.getAbsolutePath() + " is not a directory!!", f.isDirectory());
        }
        Assert.assertTrue(targetFile.getAbsolutePath() + " doesn't exist!!", targetFile.exists());

        // Now verify the contents of the file
        BufferedReader reader = new BufferedReader(new FileReader(targetFile));
        Assert.assertEquals("Hello World!", reader.readLine());
        Assert.assertEquals(null, reader.readLine());
    }

    //@Test
    public void testContainerLaunchAndStop() throws IOException, InterruptedException, YarnException {
        containerManager.start();

        File scriptFile = Shell.appendScriptExtension(tmpDir, "scriptFile");
        PrintWriter fileWriter = new PrintWriter(scriptFile);
        File processStartFile = new File(tmpDir, "start_file.txt").getAbsoluteFile();

        // ////// Construct the Container-id
        ContainerId cId = createContainerId(0);

        if (Shell.WINDOWS) {
            fileWriter.println("@echo Hello World!> " + processStartFile);
            fileWriter.println("@echo " + cId + ">> " + processStartFile);
            fileWriter.println("@ping -n 100 127.0.0.1 >nul");
        } else {
            fileWriter.write("\numask 0"); // So that start file is readable by the test
            fileWriter.write("\necho Hello World! > " + processStartFile);
            fileWriter.write("\necho $$ >> " + processStartFile);
            fileWriter.write("\nexec sleep 100");
        }
        fileWriter.close();

        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);

        URL resource_alpha = URL.fromPath(localFS.makeQualified(new Path(scriptFile.getAbsolutePath())));
        LocalResource rsrc_alpha = recordFactory.newRecordInstance(LocalResource.class);
        rsrc_alpha.setResource(resource_alpha);
        rsrc_alpha.setSize(-1);
        rsrc_alpha.setVisibility(LocalResourceVisibility.APPLICATION);
        rsrc_alpha.setType(LocalResourceType.FILE);
        rsrc_alpha.setTimestamp(scriptFile.lastModified());
        String destinationFile = "dest_file";
        Map<String, LocalResource> localResources = new HashMap<String, LocalResource>();
        localResources.put(destinationFile, rsrc_alpha);
        containerLaunchContext.setLocalResources(localResources);
        List<String> commands = Arrays.asList(Shell.getRunScriptCommand(scriptFile));
        containerLaunchContext.setCommands(commands);

        StartContainerRequest scRequest = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                        context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list = new ArrayList<StartContainerRequest>();
        list.add(scRequest);
        StartContainersRequest allRequests = StartContainersRequest.newInstance(list);
        containerManager.startContainers(allRequests);

        int timeoutSecs = 0;
        while (!processStartFile.exists() && timeoutSecs++ < 20) {
            Thread.sleep(1000);
            LOG.info("Waiting for process start-file to be created");
        }
        Assert.assertTrue("ProcessStartFile doesn't exist!", processStartFile.exists());

        // Now verify the contents of the file
        BufferedReader reader = new BufferedReader(new FileReader(processStartFile));
        Assert.assertEquals("Hello World!", reader.readLine());
        // Get the pid of the process
        String pid = reader.readLine().trim();
        // No more lines
        Assert.assertEquals(null, reader.readLine());

        // Now test the stop functionality.

        // Assert that the process is alive
        Assert.assertTrue("Process is not alive!", DefaultContainerExecutor.containerIsAlive(pid));
        // Once more
        Assert.assertTrue("Process is not alive!", DefaultContainerExecutor.containerIsAlive(pid));

        List<ContainerId> containerIds = new ArrayList<ContainerId>();
        containerIds.add(cId);
        StopContainersRequest stopRequest = StopContainersRequest.newInstance(containerIds);
        containerManager.stopContainers(stopRequest);
        BaseContainerManagerTest.waitForContainerState(containerManager, cId, ContainerState.COMPLETE);

        GetContainerStatusesRequest gcsRequest = GetContainerStatusesRequest.newInstance(containerIds);
        ContainerStatus containerStatus = containerManager.getContainerStatuses(gcsRequest).getContainerStatuses()
                .get(0);
        int expectedExitCode = ContainerExitStatus.KILLED_BY_APPMASTER;
        Assert.assertEquals(expectedExitCode, containerStatus.getExitStatus());

        // Assert that the process is not alive anymore
        Assert.assertFalse("Process is still alive!", DefaultContainerExecutor.containerIsAlive(pid));
    }

    private void testContainerLaunchAndExit(int exitCode) throws IOException, InterruptedException, YarnException {

        File scriptFile = Shell.appendScriptExtension(tmpDir, "scriptFile");
        PrintWriter fileWriter = new PrintWriter(scriptFile);
        File processStartFile = new File(tmpDir, "start_file.txt").getAbsoluteFile();

        // ////// Construct the Container-id
        ContainerId cId = createContainerId(0);

        if (Shell.WINDOWS) {
            fileWriter.println("@echo Hello World!> " + processStartFile);
            fileWriter.println("@echo " + cId + ">> " + processStartFile);
            if (exitCode != 0) {
                fileWriter.println("@exit " + exitCode);
            }
        } else {
            fileWriter.write("\numask 0"); // So that start file is readable by the test
            fileWriter.write("\necho Hello World! > " + processStartFile);
            fileWriter.write("\necho $$ >> " + processStartFile);
            // Have script throw an exit code at the end
            if (exitCode != 0) {
                fileWriter.write("\nexit " + exitCode);
            }
        }

        fileWriter.close();

        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);

        URL resource_alpha = URL.fromPath(localFS.makeQualified(new Path(scriptFile.getAbsolutePath())));
        LocalResource rsrc_alpha = recordFactory.newRecordInstance(LocalResource.class);
        rsrc_alpha.setResource(resource_alpha);
        rsrc_alpha.setSize(-1);
        rsrc_alpha.setVisibility(LocalResourceVisibility.APPLICATION);
        rsrc_alpha.setType(LocalResourceType.FILE);
        rsrc_alpha.setTimestamp(scriptFile.lastModified());
        String destinationFile = "dest_file";
        Map<String, LocalResource> localResources = new HashMap<String, LocalResource>();
        localResources.put(destinationFile, rsrc_alpha);
        containerLaunchContext.setLocalResources(localResources);
        List<String> commands = Arrays.asList(Shell.getRunScriptCommand(scriptFile));
        containerLaunchContext.setCommands(commands);

        StartContainerRequest scRequest = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                        context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list = new ArrayList<StartContainerRequest>();
        list.add(scRequest);
        StartContainersRequest allRequests = StartContainersRequest.newInstance(list);
        containerManager.startContainers(allRequests);

        BaseContainerManagerTest.waitForContainerState(containerManager, cId, ContainerState.COMPLETE);

        List<ContainerId> containerIds = new ArrayList<ContainerId>();
        containerIds.add(cId);
        GetContainerStatusesRequest gcsRequest = GetContainerStatusesRequest.newInstance(containerIds);
        ContainerStatus containerStatus = containerManager.getContainerStatuses(gcsRequest).getContainerStatuses()
                .get(0);

        // Verify exit status matches exit state of script
        Assert.assertEquals(exitCode, containerStatus.getExitStatus());
    }

    @Test
    public void testContainerLaunchAndExitSuccess() throws IOException, InterruptedException, YarnException {
        containerManager.start();
        int exitCode = 0;

        // launch context for a command that will return exit code 0 
        // and verify exit code returned 
        testContainerLaunchAndExit(exitCode);
    }

    @Test
    public void testContainerLaunchAndExitFailure() throws IOException, InterruptedException, YarnException {
        containerManager.start();
        int exitCode = 50;

        // launch context for a command that will return exit code 0 
        // and verify exit code returned 
        testContainerLaunchAndExit(exitCode);
    }

    @Test
    public void testLocalFilesCleanup() throws InterruptedException, IOException, YarnException {
        // Real del service
        delSrvc = new DeletionService(exec);
        delSrvc.init(conf);

        containerManager = createContainerManager(delSrvc);
        containerManager.init(conf);
        containerManager.start();

        // ////// Create the resources for the container
        File dir = new File(tmpDir, "dir");
        dir.mkdirs();
        File file = new File(dir, "file");
        PrintWriter fileWriter = new PrintWriter(file);
        fileWriter.write("Hello World!");
        fileWriter.close();

        // ////// Construct the Container-id
        ContainerId cId = createContainerId(0);
        ApplicationId appId = cId.getApplicationAttemptId().getApplicationId();

        // ////// Construct the container-spec.
        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);
        //    containerLaunchContext.resources =
        //        new HashMap<CharSequence, LocalResource>();
        URL resource_alpha = URL
                .fromPath(FileContext.getLocalFSFileContext().makeQualified(new Path(file.getAbsolutePath())));
        LocalResource rsrc_alpha = recordFactory.newRecordInstance(LocalResource.class);
        rsrc_alpha.setResource(resource_alpha);
        rsrc_alpha.setSize(-1);
        rsrc_alpha.setVisibility(LocalResourceVisibility.APPLICATION);
        rsrc_alpha.setType(LocalResourceType.FILE);
        rsrc_alpha.setTimestamp(file.lastModified());
        String destinationFile = "dest_file";
        Map<String, LocalResource> localResources = new HashMap<String, LocalResource>();
        localResources.put(destinationFile, rsrc_alpha);
        containerLaunchContext.setLocalResources(localResources);

        StartContainerRequest scRequest = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                        context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list = new ArrayList<StartContainerRequest>();
        list.add(scRequest);
        StartContainersRequest allRequests = StartContainersRequest.newInstance(list);
        containerManager.startContainers(allRequests);

        BaseContainerManagerTest.waitForContainerState(containerManager, cId, ContainerState.COMPLETE);

        BaseContainerManagerTest.waitForApplicationState(containerManager,
                cId.getApplicationAttemptId().getApplicationId(), ApplicationState.RUNNING);

        // Now ascertain that the resources are localised correctly.
        String appIDStr = appId.toString();
        String containerIDStr = cId.toString();
        File userCacheDir = new File(localDir, ContainerLocalizer.USERCACHE);
        File userDir = new File(userCacheDir, userFolder);
        File appCache = new File(userDir, ContainerLocalizer.APPCACHE);
        File appDir = new File(appCache, appIDStr);
        File containerDir = new File(appDir, containerIDStr);
        File targetFile = new File(containerDir, destinationFile);
        File sysDir = new File(localDir, ResourceLocalizationService.NM_PRIVATE_DIR);
        File appSysDir = new File(sysDir, appIDStr);
        File containerSysDir = new File(appSysDir, containerIDStr);
        // AppDir should still exist
        Assert.assertTrue("AppDir " + appDir.getAbsolutePath() + " doesn't exist!!", appDir.exists());
        Assert.assertTrue("AppSysDir " + appSysDir.getAbsolutePath() + " doesn't exist!!", appSysDir.exists());
        for (File f : new File[] { containerDir, containerSysDir }) {
            Assert.assertFalse(f.getAbsolutePath() + " exists!!", f.exists());
        }
        Assert.assertFalse(targetFile.getAbsolutePath() + " exists!!", targetFile.exists());

        // Simulate RM sending an AppFinish event.
        containerManager.handle(new CMgrCompletedAppsEvent(Arrays.asList(new ApplicationId[] { appId }),
                CMgrCompletedAppsEvent.Reason.ON_SHUTDOWN));

        BaseContainerManagerTest.waitForApplicationState(containerManager,
                cId.getApplicationAttemptId().getApplicationId(), ApplicationState.FINISHED);

        // Now ascertain that the resources are localised correctly.
        for (File f : new File[] { appDir, containerDir, appSysDir, containerSysDir }) {
            // Wait for deletion. Deletion can happen long after AppFinish because of
            // the async DeletionService
            int timeout = 0;
            while (f.exists() && timeout++ < 15) {
                Thread.sleep(1000);
            }
            Assert.assertFalse(f.getAbsolutePath() + " exists!!", f.exists());
        }
        // Wait for deletion
        int timeout = 0;
        while (targetFile.exists() && timeout++ < 15) {
            Thread.sleep(1000);
        }
        Assert.assertFalse(targetFile.getAbsolutePath() + " exists!!", targetFile.exists());
    }

    @Test
    public void testContainerLaunchFromPreviousRM() throws IOException, InterruptedException, YarnException {
        containerManager.start();

        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);

        ContainerId cId1 = createContainerId(0);
        ContainerId cId2 = createContainerId(0);
        containerLaunchContext.setLocalResources(new HashMap<String, LocalResource>());

        // Construct the Container with Invalid RMIdentifier
        StartContainerRequest startRequest1 = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId1, ResourceManagerConstants.RM_INVALID_IDENTIFIER, context.getNodeId(),
                        user, context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list = new ArrayList<StartContainerRequest>();
        list.add(startRequest1);
        StartContainersRequest allRequests = StartContainersRequest.newInstance(list);
        containerManager.startContainers(allRequests);

        boolean catchException = false;
        try {
            StartContainersResponse response = containerManager.startContainers(allRequests);
            if (response.getFailedRequests().containsKey(cId1)) {
                throw response.getFailedRequests().get(cId1).deSerialize();
            }
        } catch (Throwable e) {
            e.printStackTrace();
            catchException = true;
            Assert.assertTrue(
                    e.getMessage().contains("Container " + cId1 + " rejected as it is allocated by a previous RM"));
            Assert.assertTrue(e.getClass().getName().equalsIgnoreCase(InvalidContainerException.class.getName()));
        }

        // Verify that startContainer fail because of invalid container request
        Assert.assertTrue(catchException);

        // Construct the Container with a RMIdentifier within current RM
        StartContainerRequest startRequest2 = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId2, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                        context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list2 = new ArrayList<StartContainerRequest>();
        list.add(startRequest2);
        StartContainersRequest allRequests2 = StartContainersRequest.newInstance(list2);
        containerManager.startContainers(allRequests2);

        boolean noException = true;
        try {
            containerManager.startContainers(allRequests2);
        } catch (YarnException e) {
            noException = false;
        }
        // Verify that startContainer get no YarnException
        Assert.assertTrue(noException);
    }

    @Test
    public void testMultipleContainersLaunch() throws Exception {
        containerManager.start();

        List<StartContainerRequest> list = new ArrayList<StartContainerRequest>();
        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);
        for (int i = 0; i < 10; i++) {
            ContainerId cId = createContainerId(i);
            long identifier = 0;
            if ((i & 1) == 0)
                // container with even id fail
                identifier = ResourceManagerConstants.RM_INVALID_IDENTIFIER;
            else
                identifier = DUMMY_RM_IDENTIFIER;
            Token containerToken = createContainerToken(cId, identifier, context.getNodeId(), user,
                    context.getContainerTokenSecretManager(), userFolder);
            StartContainerRequest request = StartContainerRequest.newInstance(containerLaunchContext,
                    containerToken);
            list.add(request);
        }
        StartContainersRequest requestList = StartContainersRequest.newInstance(list);

        StartContainersResponse response = containerManager.startContainers(requestList);

        Assert.assertEquals(5, response.getSuccessfullyStartedContainers().size());
        for (ContainerId id : response.getSuccessfullyStartedContainers()) {
            // Containers with odd id should succeed.
            Assert.assertEquals(1, id.getContainerId() & 1);
        }
        Assert.assertEquals(5, response.getFailedRequests().size());
        for (Map.Entry<ContainerId, SerializedException> entry : response.getFailedRequests().entrySet()) {
            // Containers with even id should fail.
            Assert.assertEquals(0, entry.getKey().getContainerId() & 1);
            Assert.assertTrue(entry.getValue().getMessage()
                    .contains("Container " + entry.getKey() + " rejected as it is allocated by a previous RM"));
        }
    }

    @Test
    public void testMultipleContainersStopAndGetStatus() throws Exception {
        containerManager.start();
        List<StartContainerRequest> startRequest = new ArrayList<StartContainerRequest>();
        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);

        List<ContainerId> containerIds = new ArrayList<ContainerId>();
        for (int i = 0; i < 10; i++) {
            ContainerId cId;
            if ((i & 1) == 0) {
                // Containers with even id belong to an unauthorized app
                cId = createContainerId(i, 1);
            } else {
                cId = createContainerId(i, 0);
            }
            Token containerToken = createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                    context.getContainerTokenSecretManager(), userFolder);
            StartContainerRequest request = StartContainerRequest.newInstance(containerLaunchContext,
                    containerToken);
            startRequest.add(request);
            containerIds.add(cId);
        }
        // start containers
        StartContainersRequest requestList = StartContainersRequest.newInstance(startRequest);
        containerManager.startContainers(requestList);

        // Get container statuses
        GetContainerStatusesRequest statusRequest = GetContainerStatusesRequest.newInstance(containerIds);
        GetContainerStatusesResponse statusResponse = containerManager.getContainerStatuses(statusRequest);
        Assert.assertEquals(5, statusResponse.getContainerStatuses().size());
        for (ContainerStatus status : statusResponse.getContainerStatuses()) {
            // Containers with odd id should succeed
            Assert.assertEquals(1, status.getContainerId().getContainerId() & 1);
        }
        Assert.assertEquals(5, statusResponse.getFailedRequests().size());
        for (Map.Entry<ContainerId, SerializedException> entry : statusResponse.getFailedRequests().entrySet()) {
            // Containers with even id should fail.
            Assert.assertEquals(0, entry.getKey().getContainerId() & 1);
            Assert.assertTrue(entry.getValue().getMessage()
                    .contains("attempted to get status for non-application container"));
        }

        // stop containers
        StopContainersRequest stopRequest = StopContainersRequest.newInstance(containerIds);
        StopContainersResponse stopResponse = containerManager.stopContainers(stopRequest);
        Assert.assertEquals(5, stopResponse.getSuccessfullyStoppedContainers().size());
        for (ContainerId id : stopResponse.getSuccessfullyStoppedContainers()) {
            // Containers with odd id should succeed.
            Assert.assertEquals(1, id.getContainerId() & 1);
        }
        Assert.assertEquals(5, stopResponse.getFailedRequests().size());
        for (Map.Entry<ContainerId, SerializedException> entry : stopResponse.getFailedRequests().entrySet()) {
            // Containers with even id should fail.
            Assert.assertEquals(0, entry.getKey().getContainerId() & 1);
            Assert.assertTrue(
                    entry.getValue().getMessage().contains("attempted to stop non-application container"));
        }
    }

    @Test
    public void testUnauthorizedRequests() throws IOException, YarnException {
        containerManager.start();

        // Create a containerId that belongs to an unauthorized appId
        ContainerId cId = createContainerId(0, 1);

        // startContainers()
        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);
        StartContainerRequest scRequest = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                        context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list = new ArrayList<>();
        list.add(scRequest);
        StartContainersRequest allRequests = StartContainersRequest.newInstance(list);
        StartContainersResponse startResponse = containerManager.startContainers(allRequests);

        Assert.assertFalse("Should not be authorized to start container",
                startResponse.getSuccessfullyStartedContainers().contains(cId));
        Assert.assertTrue("Start container request should fail",
                startResponse.getFailedRequests().containsKey(cId));

        // Insert the containerId into context, make it as if it is running
        ContainerTokenIdentifier containerTokenIdentifier = BuilderUtils
                .newContainerTokenIdentifier(scRequest.getContainerToken());
        Container container = new ContainerImpl(conf, null, containerLaunchContext, null, metrics,
                containerTokenIdentifier, context);
        context.getContainers().put(cId, container);

        // stopContainers()
        List<ContainerId> containerIds = new ArrayList<>();
        containerIds.add(cId);
        StopContainersRequest stopRequest = StopContainersRequest.newInstance(containerIds);
        StopContainersResponse stopResponse = containerManager.stopContainers(stopRequest);

        Assert.assertFalse("Should not be authorized to stop container",
                stopResponse.getSuccessfullyStoppedContainers().contains(cId));
        Assert.assertTrue("Stop container request should fail", stopResponse.getFailedRequests().containsKey(cId));

        // getContainerStatuses()
        containerIds = new ArrayList<>();
        containerIds.add(cId);
        GetContainerStatusesRequest request = GetContainerStatusesRequest.newInstance(containerIds);
        GetContainerStatusesResponse response = containerManager.getContainerStatuses(request);

        Assert.assertEquals("Should not be authorized to get container status",
                response.getContainerStatuses().size(), 0);
        Assert.assertTrue("Get status request should fail", response.getFailedRequests().containsKey(cId));
    }

    @Test
    public void testStartContainerFailureWithUnknownAuxService() throws Exception {
        conf.setStrings(YarnConfiguration.NM_AUX_SERVICES, new String[] { "existService" });
        conf.setClass(String.format(YarnConfiguration.NM_AUX_SERVICE_FMT, "existService"), ServiceA.class,
                Service.class);
        containerManager.start();

        List<StartContainerRequest> startRequest = new ArrayList<StartContainerRequest>();

        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);
        Map<String, ByteBuffer> serviceData = new HashMap<String, ByteBuffer>();
        String serviceName = "non_exist_auxService";
        serviceData.put(serviceName, ByteBuffer.wrap(serviceName.getBytes()));
        containerLaunchContext.setServiceData(serviceData);

        ContainerId cId = createContainerId(0);
        String user = "start_container_fail";
        Token containerToken = createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                context.getContainerTokenSecretManager(), userFolder);
        StartContainerRequest request = StartContainerRequest.newInstance(containerLaunchContext, containerToken);

        // start containers
        startRequest.add(request);
        StartContainersRequest requestList = StartContainersRequest.newInstance(startRequest);

        StartContainersResponse response = containerManager.startContainers(requestList);
        Assert.assertTrue(response.getFailedRequests().size() == 1);
        Assert.assertTrue(response.getSuccessfullyStartedContainers().size() == 0);
        Assert.assertTrue(response.getFailedRequests().containsKey(cId));
        Assert.assertTrue(response.getFailedRequests().get(cId).getMessage()
                .contains("The auxService:" + serviceName + " does not exist"));
    }

    /* Test added to verify fix in YARN-644 */
    @Test
    public void testNullTokens() throws Exception {
        ContainerManagerImpl cMgrImpl = new ContainerManagerImpl(context, exec, delSrvc, nodeStatusUpdater, metrics,
                dirsHandler);
        String strExceptionMsg = "";
        try {
            cMgrImpl.authorizeStartAndResourceIncreaseRequest(null, new ContainerTokenIdentifier(), true);
        } catch (YarnException ye) {
            strExceptionMsg = ye.getMessage();
        }
        Assert.assertEquals(strExceptionMsg, ContainerManagerImpl.INVALID_NMTOKEN_MSG);

        strExceptionMsg = "";
        try {
            cMgrImpl.authorizeStartAndResourceIncreaseRequest(new NMTokenIdentifier(), null, true);
        } catch (YarnException ye) {
            strExceptionMsg = ye.getMessage();
        }
        Assert.assertEquals(strExceptionMsg, ContainerManagerImpl.INVALID_CONTAINERTOKEN_MSG);

        strExceptionMsg = "";
        try {
            cMgrImpl.authorizeGetAndStopContainerRequest(null, null, true, null);
        } catch (YarnException ye) {
            strExceptionMsg = ye.getMessage();
        }
        Assert.assertEquals(strExceptionMsg, ContainerManagerImpl.INVALID_NMTOKEN_MSG);

        strExceptionMsg = "";
        try {
            cMgrImpl.authorizeUser(null, null);
        } catch (YarnException ye) {
            strExceptionMsg = ye.getMessage();
        }
        Assert.assertEquals(strExceptionMsg, ContainerManagerImpl.INVALID_NMTOKEN_MSG);

        ContainerManagerImpl spyContainerMgr = Mockito.spy(cMgrImpl);
        UserGroupInformation ugInfo = UserGroupInformation.createRemoteUser("a");
        Mockito.when(spyContainerMgr.getRemoteUgi()).thenReturn(ugInfo);
        Mockito.when(spyContainerMgr.selectNMTokenIdentifier(ugInfo)).thenReturn(null);

        strExceptionMsg = "";
        try {
            spyContainerMgr.stopContainers(new StopContainersRequestPBImpl());
        } catch (YarnException ye) {
            strExceptionMsg = ye.getMessage();
        }
        Assert.assertEquals(strExceptionMsg, ContainerManagerImpl.INVALID_NMTOKEN_MSG);

        strExceptionMsg = "";
        try {
            spyContainerMgr.getContainerStatuses(new GetContainerStatusesRequestPBImpl());
        } catch (YarnException ye) {
            strExceptionMsg = ye.getMessage();
        }
        Assert.assertEquals(strExceptionMsg, ContainerManagerImpl.INVALID_NMTOKEN_MSG);

        Mockito.doNothing().when(spyContainerMgr).authorizeUser(ugInfo, null);
        List<StartContainerRequest> reqList = new ArrayList<StartContainerRequest>();
        reqList.add(StartContainerRequest.newInstance(null, null));
        StartContainersRequest reqs = new StartContainersRequestPBImpl();
        reqs.setStartContainerRequests(reqList);
        strExceptionMsg = "";
        try {
            spyContainerMgr.startContainers(reqs);
        } catch (YarnException ye) {
            strExceptionMsg = ye.getCause().getMessage();
        }
        Assert.assertEquals(strExceptionMsg, ContainerManagerImpl.INVALID_CONTAINERTOKEN_MSG);
    }

    @Test
    public void testIncreaseContainerResourceWithInvalidRequests() throws Exception {
        containerManager.start();
        // Start 4 containers 0..4 with default resource (1024, 1)
        List<StartContainerRequest> list = new ArrayList<>();
        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);
        for (int i = 0; i < 4; i++) {
            ContainerId cId = createContainerId(i);
            long identifier = DUMMY_RM_IDENTIFIER;
            Token containerToken = createContainerToken(cId, identifier, context.getNodeId(), user,
                    context.getContainerTokenSecretManager(), userFolder);
            StartContainerRequest request = StartContainerRequest.newInstance(containerLaunchContext,
                    containerToken);
            list.add(request);
        }
        StartContainersRequest requestList = StartContainersRequest.newInstance(list);
        StartContainersResponse response = containerManager.startContainers(requestList);

        Assert.assertEquals(4, response.getSuccessfullyStartedContainers().size());
        int i = 0;
        for (ContainerId id : response.getSuccessfullyStartedContainers()) {
            Assert.assertEquals(i, id.getContainerId());
            i++;
        }

        Thread.sleep(2000);
        // Construct container resource increase request,
        List<Token> increaseTokens = new ArrayList<Token>();
        // Add increase request for container-0, the request will fail as the
        // container will have exited, and won't be in RUNNING state
        ContainerId cId0 = createContainerId(0);
        Token containerToken = createContainerToken(cId0, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                Resource.newInstance(1234, 3), context.getContainerTokenSecretManager(), null, userFolder);
        increaseTokens.add(containerToken);
        // Add increase request for container-7, the request will fail as the
        // container does not exist
        ContainerId cId7 = createContainerId(7);
        containerToken = createContainerToken(cId7, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                Resource.newInstance(1234, 3), context.getContainerTokenSecretManager(), null, userFolder);
        increaseTokens.add(containerToken);

        IncreaseContainersResourceRequest increaseRequest = IncreaseContainersResourceRequest
                .newInstance(increaseTokens);
        IncreaseContainersResourceResponse increaseResponse = containerManager
                .increaseContainersResource(increaseRequest);
        // Check response
        Assert.assertEquals(0, increaseResponse.getSuccessfullyIncreasedContainers().size());
        Assert.assertEquals(2, increaseResponse.getFailedRequests().size());
        for (Map.Entry<ContainerId, SerializedException> entry : increaseResponse.getFailedRequests().entrySet()) {
            Assert.assertNotNull("Failed message", entry.getValue().getMessage());
            if (cId0.equals(entry.getKey())) {
                Assert.assertTrue(entry.getValue().getMessage()
                        .contains("Resource can only be changed when a " + "container is in RUNNING state"));
            } else if (cId7.equals(entry.getKey())) {
                Assert.assertTrue(entry.getValue().getMessage()
                        .contains("Container " + cId7.toString() + " is not handled by this NodeManager"));
            } else {
                throw new YarnException(
                        "Received failed request from wrong" + " container: " + entry.getKey().toString());
            }
        }
    }

    @Test
    public void testIncreaseContainerResourceWithInvalidResource() throws Exception {
        containerManager.start();
        File scriptFile = Shell.appendScriptExtension(tmpDir, "scriptFile");
        PrintWriter fileWriter = new PrintWriter(scriptFile);
        // Construct the Container-id
        ContainerId cId = createContainerId(0);
        if (Shell.WINDOWS) {
            fileWriter.println("@ping -n 100 127.0.0.1 >nul");
        } else {
            fileWriter.write("\numask 0");
            fileWriter.write("\nexec sleep 100");
        }
        fileWriter.close();
        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);
        URL resource_alpha = URL.fromPath(localFS.makeQualified(new Path(scriptFile.getAbsolutePath())));
        LocalResource rsrc_alpha = recordFactory.newRecordInstance(LocalResource.class);
        rsrc_alpha.setResource(resource_alpha);
        rsrc_alpha.setSize(-1);
        rsrc_alpha.setVisibility(LocalResourceVisibility.APPLICATION);
        rsrc_alpha.setType(LocalResourceType.FILE);
        rsrc_alpha.setTimestamp(scriptFile.lastModified());
        String destinationFile = "dest_file";
        Map<String, LocalResource> localResources = new HashMap<String, LocalResource>();
        localResources.put(destinationFile, rsrc_alpha);
        containerLaunchContext.setLocalResources(localResources);
        List<String> commands = Arrays.asList(Shell.getRunScriptCommand(scriptFile));
        containerLaunchContext.setCommands(commands);

        StartContainerRequest scRequest = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                        context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list = new ArrayList<StartContainerRequest>();
        list.add(scRequest);
        StartContainersRequest allRequests = StartContainersRequest.newInstance(list);
        containerManager.startContainers(allRequests);
        // Make sure the container reaches RUNNING state
        BaseContainerManagerTest.waitForNMContainerState(containerManager, cId,
                org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerState.RUNNING);
        // Construct container resource increase request,
        List<Token> increaseTokens = new ArrayList<Token>();
        // Add increase request. The increase request should fail
        // as the current resource does not fit in the target resource
        Token containerToken = createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                Resource.newInstance(512, 1), context.getContainerTokenSecretManager(), null, userFolder);
        increaseTokens.add(containerToken);
        IncreaseContainersResourceRequest increaseRequest = IncreaseContainersResourceRequest
                .newInstance(increaseTokens);
        IncreaseContainersResourceResponse increaseResponse = containerManager
                .increaseContainersResource(increaseRequest);
        // Check response
        Assert.assertEquals(0, increaseResponse.getSuccessfullyIncreasedContainers().size());
        Assert.assertEquals(1, increaseResponse.getFailedRequests().size());
        for (Map.Entry<ContainerId, SerializedException> entry : increaseResponse.getFailedRequests().entrySet()) {
            if (cId.equals(entry.getKey())) {
                Assert.assertNotNull("Failed message", entry.getValue().getMessage());
                Assert.assertTrue(entry.getValue().getMessage()
                        .contains("The target resource " + Resource.newInstance(512, 1).toString()
                                + " is smaller than the current resource " + Resource.newInstance(1024, 1)));
            } else {
                throw new YarnException(
                        "Received failed request from wrong" + " container: " + entry.getKey().toString());
            }
        }
    }

    @Test
    public void testChangeContainerResource() throws Exception {
        containerManager.start();
        File scriptFile = Shell.appendScriptExtension(tmpDir, "scriptFile");
        PrintWriter fileWriter = new PrintWriter(scriptFile);
        // Construct the Container-id
        ContainerId cId = createContainerId(0);
        if (Shell.WINDOWS) {
            fileWriter.println("@ping -n 100 127.0.0.1 >nul");
        } else {
            fileWriter.write("\numask 0");
            fileWriter.write("\nexec sleep 100");
        }
        fileWriter.close();
        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);
        URL resource_alpha = URL.fromPath(localFS.makeQualified(new Path(scriptFile.getAbsolutePath())));
        LocalResource rsrc_alpha = recordFactory.newRecordInstance(LocalResource.class);
        rsrc_alpha.setResource(resource_alpha);
        rsrc_alpha.setSize(-1);
        rsrc_alpha.setVisibility(LocalResourceVisibility.APPLICATION);
        rsrc_alpha.setType(LocalResourceType.FILE);
        rsrc_alpha.setTimestamp(scriptFile.lastModified());
        String destinationFile = "dest_file";
        Map<String, LocalResource> localResources = new HashMap<String, LocalResource>();
        localResources.put(destinationFile, rsrc_alpha);
        containerLaunchContext.setLocalResources(localResources);
        List<String> commands = Arrays.asList(Shell.getRunScriptCommand(scriptFile));
        containerLaunchContext.setCommands(commands);
        StartContainerRequest scRequest = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                        context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list = new ArrayList<StartContainerRequest>();
        list.add(scRequest);
        StartContainersRequest allRequests = StartContainersRequest.newInstance(list);
        containerManager.startContainers(allRequests);
        // Make sure the container reaches RUNNING state
        BaseContainerManagerTest.waitForNMContainerState(containerManager, cId,
                org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerState.RUNNING);
        // Construct container resource increase request,
        List<Token> increaseTokens = new ArrayList<Token>();
        // Add increase request.
        Resource targetResource = Resource.newInstance(4096, 2);
        Token containerToken = createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                targetResource, context.getContainerTokenSecretManager(), null, userFolder);
        increaseTokens.add(containerToken);
        IncreaseContainersResourceRequest increaseRequest = IncreaseContainersResourceRequest
                .newInstance(increaseTokens);
        IncreaseContainersResourceResponse increaseResponse = containerManager
                .increaseContainersResource(increaseRequest);
        Assert.assertEquals(1, increaseResponse.getSuccessfullyIncreasedContainers().size());
        Assert.assertTrue(increaseResponse.getFailedRequests().isEmpty());
        // Check status
        List<ContainerId> containerIds = new ArrayList<>();
        containerIds.add(cId);
        GetContainerStatusesRequest gcsRequest = GetContainerStatusesRequest.newInstance(containerIds);
        ContainerStatus containerStatus = containerManager.getContainerStatuses(gcsRequest).getContainerStatuses()
                .get(0);
        // Check status immediately as resource increase is blocking
        assertEquals(targetResource, containerStatus.getCapability());
        // Simulate a decrease request
        List<org.apache.hadoop.yarn.api.records.Container> containersToDecrease = new ArrayList<>();
        targetResource = Resource.newInstance(2048, 2);
        org.apache.hadoop.yarn.api.records.Container decreasedContainer = org.apache.hadoop.yarn.api.records.Container
                .newInstance(cId, null, null, targetResource, null, null);
        containersToDecrease.add(decreasedContainer);
        containerManager.handle(new CMgrDecreaseContainersResourceEvent(containersToDecrease));
        // Check status with retry
        containerStatus = containerManager.getContainerStatuses(gcsRequest).getContainerStatuses().get(0);
        int retry = 0;
        while (!targetResource.equals(containerStatus.getCapability()) && (retry++ < 5)) {
            Thread.sleep(200);
            containerStatus = containerManager.getContainerStatuses(gcsRequest).getContainerStatuses().get(0);
        }
        assertEquals(targetResource, containerStatus.getCapability());
    }

    public static Token createContainerToken(ContainerId cId, long rmIdentifier, NodeId nodeId, String user,
            NMContainerTokenSecretManager containerTokenSecretManager, String userFolder) throws IOException {
        return createContainerToken(cId, rmIdentifier, nodeId, user, containerTokenSecretManager, null, userFolder);
    }

    public static Token createContainerToken(ContainerId cId, long rmIdentifier, NodeId nodeId, String user,
            NMContainerTokenSecretManager containerTokenSecretManager, LogAggregationContext logAggregationContext,
            String userFolder) throws IOException {
        Resource r = BuilderUtils.newResource(1024, 1);
        return createContainerToken(cId, rmIdentifier, nodeId, user, r, containerTokenSecretManager,
                logAggregationContext, userFolder);
    }

    public static Token createContainerToken(ContainerId cId, long rmIdentifier, NodeId nodeId, String user,
            Resource resource, NMContainerTokenSecretManager containerTokenSecretManager,
            LogAggregationContext logAggregationContext, String userFolder) throws IOException {
        ContainerTokenIdentifier containerTokenIdentifier = new ContainerTokenIdentifier(cId, nodeId.toString(),
                user, resource, System.currentTimeMillis() + 100000L, 123, rmIdentifier, Priority.newInstance(0), 0,
                logAggregationContext, null, userFolder);
        return BuilderUtils.newContainerToken(nodeId,
                containerTokenSecretManager.retrievePassword(containerTokenIdentifier), containerTokenIdentifier);
    }

    @Test
    public void testOutputThreadDumpSignal() throws IOException, InterruptedException, YarnException {
        testContainerLaunchAndSignal(SignalContainerCommand.OUTPUT_THREAD_DUMP);
    }

    @Test
    public void testGracefulShutdownSignal() throws IOException, InterruptedException, YarnException {
        testContainerLaunchAndSignal(SignalContainerCommand.GRACEFUL_SHUTDOWN);
    }

    @Test
    public void testForcefulShutdownSignal() throws IOException, InterruptedException, YarnException {
        testContainerLaunchAndSignal(SignalContainerCommand.FORCEFUL_SHUTDOWN);
    }

    // Verify signal container request can be delivered from
    // NodeStatusUpdaterImpl to ContainerExecutor.
    private void testContainerLaunchAndSignal(SignalContainerCommand command)
            throws IOException, InterruptedException, YarnException {

        Signal signal = ContainerLaunch.translateCommandToSignal(command);
        containerManager.start();

        File scriptFile = new File(tmpDir, "scriptFile.sh");
        PrintWriter fileWriter = new PrintWriter(scriptFile);
        File processStartFile = new File(tmpDir, "start_file.txt").getAbsoluteFile();
        fileWriter.write("\numask 0"); // So that start file is readable by the test
        fileWriter.write("\necho Hello World! > " + processStartFile);
        fileWriter.write("\necho $$ >> " + processStartFile);
        fileWriter.write("\nexec sleep 1000s");
        fileWriter.close();

        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);

        // ////// Construct the Container-id
        ContainerId cId = createContainerId(0);

        URL resource_alpha = URL.fromPath(localFS.makeQualified(new Path(scriptFile.getAbsolutePath())));
        LocalResource rsrc_alpha = recordFactory.newRecordInstance(LocalResource.class);
        rsrc_alpha.setResource(resource_alpha);
        rsrc_alpha.setSize(-1);
        rsrc_alpha.setVisibility(LocalResourceVisibility.APPLICATION);
        rsrc_alpha.setType(LocalResourceType.FILE);
        rsrc_alpha.setTimestamp(scriptFile.lastModified());
        String destinationFile = "dest_file";
        Map<String, LocalResource> localResources = new HashMap<String, LocalResource>();
        localResources.put(destinationFile, rsrc_alpha);
        containerLaunchContext.setLocalResources(localResources);
        List<String> commands = new ArrayList<String>();
        commands.add("/bin/bash");
        commands.add(scriptFile.getAbsolutePath());
        containerLaunchContext.setCommands(commands);
        StartContainerRequest scRequest = StartContainerRequest.newInstance(containerLaunchContext,
                createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                        context.getContainerTokenSecretManager(), userFolder));
        List<StartContainerRequest> list = new ArrayList<StartContainerRequest>();
        list.add(scRequest);
        StartContainersRequest allRequests = StartContainersRequest.newInstance(list);
        containerManager.startContainers(allRequests);

        int timeoutSecs = 0;
        while (!processStartFile.exists() && timeoutSecs++ < 20) {
            Thread.sleep(1000);
            LOG.info("Waiting for process start-file to be created");
        }
        Assert.assertTrue("ProcessStartFile doesn't exist!", processStartFile.exists());

        // Simulate NodeStatusUpdaterImpl sending CMgrSignalContainersEvent
        SignalContainerRequest signalReq = SignalContainerRequest.newInstance(cId, command);
        List<SignalContainerRequest> reqs = new ArrayList<SignalContainerRequest>();
        reqs.add(signalReq);
        containerManager.handle(new CMgrSignalContainersEvent(reqs));

        final ArgumentCaptor<ContainerSignalContext> signalContextCaptor = ArgumentCaptor
                .forClass(ContainerSignalContext.class);
        if (signal.equals(Signal.NULL)) {
            verify(exec, never()).signalContainer(signalContextCaptor.capture());
        } else {
            verify(exec, timeout(10000).atLeastOnce()).signalContainer(signalContextCaptor.capture());
            ContainerSignalContext signalContext = signalContextCaptor.getAllValues().get(0);
            Assert.assertEquals(cId, signalContext.getContainer().getContainerId());
            Assert.assertEquals(signal, signalContext.getSignal());
        }
    }

    @Test
    public void testStartContainerFailureWithInvalidLocalResource() throws Exception {
        containerManager.start();
        LocalResource rsrc_alpha = recordFactory.newRecordInstance(LocalResource.class);
        rsrc_alpha.setResource(null);
        rsrc_alpha.setSize(-1);
        rsrc_alpha.setVisibility(LocalResourceVisibility.APPLICATION);
        rsrc_alpha.setType(LocalResourceType.FILE);
        rsrc_alpha.setTimestamp(System.currentTimeMillis());
        Map<String, LocalResource> localResources = new HashMap<String, LocalResource>();
        localResources.put("invalid_resource", rsrc_alpha);
        ContainerLaunchContext containerLaunchContext = recordFactory
                .newRecordInstance(ContainerLaunchContext.class);
        ContainerLaunchContext spyContainerLaunchContext = Mockito.spy(containerLaunchContext);
        Mockito.when(spyContainerLaunchContext.getLocalResources()).thenReturn(localResources);

        ContainerId cId = createContainerId(0);
        String user = "start_container_fail";
        Token containerToken = createContainerToken(cId, DUMMY_RM_IDENTIFIER, context.getNodeId(), user,
                context.getContainerTokenSecretManager(), userFolder);
        StartContainerRequest request = StartContainerRequest.newInstance(spyContainerLaunchContext,
                containerToken);

        // start containers
        List<StartContainerRequest> startRequest = new ArrayList<StartContainerRequest>();
        startRequest.add(request);
        StartContainersRequest requestList = StartContainersRequest.newInstance(startRequest);

        StartContainersResponse response = containerManager.startContainers(requestList);
        Assert.assertTrue(response.getFailedRequests().size() == 1);
        Assert.assertTrue(response.getSuccessfullyStartedContainers().size() == 0);
        Assert.assertTrue(response.getFailedRequests().containsKey(cId));
        Assert.assertTrue(response.getFailedRequests().get(cId).getMessage()
                .contains("Null resource URL for local resource"));
    }
}