You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2016/10/04 02:20:47 UTC

[1/4] mesos git commit: Cleanups to make code more consistent.

Repository: mesos
Updated Branches:
  refs/heads/master bb397f402 -> 548dfd2be


Cleanups to make code more consistent.

Review: https://reviews.apache.org/r/52475


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/548dfd2b
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/548dfd2b
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/548dfd2b

Branch: refs/heads/master
Commit: 548dfd2be1dece9f2980d0d33e77344044fa7aaf
Parents: 8ecea16
Author: Benjamin Hindman <be...@gmail.com>
Authored: Sun Oct 2 20:13:58 2016 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Mon Oct 3 19:20:26 2016 -0700

----------------------------------------------------------------------
 .../containerizer/mesos_containerizer_tests.cpp | 106 +++++++++++--------
 1 file changed, 60 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/548dfd2b/src/tests/containerizer/mesos_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/mesos_containerizer_tests.cpp b/src/tests/containerizer/mesos_containerizer_tests.cpp
index 7872c74..ad20702 100644
--- a/src/tests/containerizer/mesos_containerizer_tests.cpp
+++ b/src/tests/containerizer/mesos_containerizer_tests.cpp
@@ -203,7 +203,7 @@ class MesosContainerizerIsolatorPreparationTest : public MesosTest
 public:
   // Construct a MesosContainerizer with MockIsolator(s) which return
   // the provided ContainerLaunchInfo for Isolator::prepare.
-  Try<Owned<MesosContainerizer>> CreateContainerizer(
+  Try<MesosContainerizer*> createContainerizer(
       Fetcher* fetcher,
       const vector<Option<ContainerLaunchInfo>>& launchInfos)
   {
@@ -239,24 +239,22 @@ public:
       return Error("Failed to create provisioner: " + provisioner.error());
     }
 
-    return Owned<MesosContainerizer>(new MesosContainerizer(
+    return new MesosContainerizer(
         flags,
         false,
         fetcher,
         Owned<ContainerLogger>(logger.get()),
         Owned<Launcher>(launcher.get()),
         provisioner->share(),
-        isolators));
+        isolators);
   }
 
-  Try<Owned<MesosContainerizer>> CreateContainerizer(
+  Try<MesosContainerizer*> createContainerizer(
       Fetcher* fetcher,
       const Option<ContainerLaunchInfo>& launchInfo)
   {
-    vector<Option<ContainerLaunchInfo>> launchInfos;
-    launchInfos.push_back(launchInfo);
-
-    return CreateContainerizer(fetcher, launchInfos);
+    vector<Option<ContainerLaunchInfo>> launchInfos = {launchInfo};
+    return createContainerizer(fetcher, launchInfos);
   }
 };
 
@@ -272,15 +270,18 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ScriptSucceeds)
   ContainerLaunchInfo launchInfo;
   launchInfo.add_pre_exec_commands()->set_value("touch " + file);
 
-  Try<Owned<MesosContainerizer>> containerizer = CreateContainerizer(
+  Try<MesosContainerizer*> create = createContainerizer(
       &fetcher,
       launchInfo);
-  ASSERT_SOME(containerizer);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
 
-  Future<bool> launch = containerizer.get()->launch(
+  Future<bool> launch = containerizer->launch(
       containerId,
       None(),
       createExecutorInfo("executor", "exit 0"),
@@ -294,8 +295,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ScriptSucceeds)
   AWAIT_READY(launch);
 
   // Wait for the child (preparation script + executor) to complete.
-  Future<Option<ContainerTermination>> wait =
-    containerizer.get()->wait(containerId);
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
 
   AWAIT_READY(wait);
   ASSERT_SOME(wait.get());
@@ -308,7 +308,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ScriptSucceeds)
   EXPECT_TRUE(os::exists(file));
 
   // Destroy the container.
-  containerizer.get()->destroy(containerId);
+  containerizer->destroy(containerId);
 }
 
 
@@ -324,16 +324,18 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ScriptFails)
   launchInfo.add_pre_exec_commands()->set_value(
       "touch " + file + " && exit 1");
 
-  Try<Owned<MesosContainerizer>> containerizer = CreateContainerizer(
+  Try<MesosContainerizer*> create = createContainerizer(
       &fetcher,
       launchInfo);
 
-  ASSERT_SOME(containerizer);
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
 
-  Future<bool> launch = containerizer.get()->launch(
+  Future<bool> launch = containerizer->launch(
       containerId,
       None(),
       createExecutorInfo("executor", "exit 0"),
@@ -347,8 +349,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ScriptFails)
   AWAIT_READY(launch);
 
   // Wait for the child (preparation script + executor) to complete.
-  Future<Option<ContainerTermination>> wait =
-    containerizer.get()->wait(containerId);
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
 
   AWAIT_READY(wait);
   ASSERT_SOME(wait.get());
@@ -361,7 +362,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ScriptFails)
   EXPECT_TRUE(os::exists(file));
 
   // Destroy the container.
-  containerizer.get()->destroy(containerId);
+  containerizer->destroy(containerId);
 }
 
 
@@ -389,15 +390,18 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, MultipleScripts)
 
   Fetcher fetcher;
 
-  Try<Owned<MesosContainerizer>> containerizer =
-    CreateContainerizer(&fetcher, launchInfos);
+  Try<MesosContainerizer*> create = createContainerizer(
+      &fetcher,
+      launchInfos);
 
-  ASSERT_SOME(containerizer);
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
 
-  Future<bool> launch = containerizer.get()->launch(
+  Future<bool> launch = containerizer->launch(
       containerId,
       None(),
       createExecutorInfo("executor", "exit 0"),
@@ -411,8 +415,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, MultipleScripts)
   AWAIT_READY(launch);
 
   // Wait for the child (preparation script(s) + executor) to complete.
-  Future<Option<ContainerTermination>> wait =
-    containerizer.get()->wait(containerId);
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
 
   AWAIT_READY(wait);
   ASSERT_SOME(wait.get());
@@ -425,7 +428,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, MultipleScripts)
   EXPECT_TRUE(os::exists(file2));
 
   // Destroy the container.
-  containerizer.get()->destroy(containerId);
+  containerizer->destroy(containerId);
 }
 
 
@@ -453,11 +456,13 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ExecutorEnvironmentVariable)
   variable->set_name("TEST_ENVIRONMENT");
   variable->set_value(file);
 
-  Try<Owned<MesosContainerizer>> containerizer = CreateContainerizer(
+  Try<MesosContainerizer*> create = createContainerizer(
       &fetcher,
       launchInfo);
 
-  ASSERT_SOME(containerizer);
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
@@ -481,7 +486,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ExecutorEnvironmentVariable)
       PID<Slave>(),
       false);
 
-  Future<bool> launch = containerizer.get()->launch(
+  Future<bool> launch = containerizer->launch(
       containerId,
       None(),
       executorInfo,
@@ -495,8 +500,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ExecutorEnvironmentVariable)
   AWAIT_READY(launch);
 
   // Wait for the child (preparation script + executor) to complete.
-  Future<Option<ContainerTermination>> wait =
-    containerizer.get()->wait(containerId);
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
 
   AWAIT_READY(wait);
   ASSERT_SOME(wait.get());
@@ -509,7 +513,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ExecutorEnvironmentVariable)
   EXPECT_TRUE(os::exists(file));
 
   // Destroy the container.
-  containerizer.get()->destroy(containerId);
+  containerizer->destroy(containerId);
 
   // Reset LIBPROCESS_IP if necessary.
   if (libprocessIP.isSome()) {
@@ -532,11 +536,14 @@ TEST_F(MesosContainerizerExecuteTest, IoRedirection)
   Fetcher fetcher;
 
   // Use local=false so std{err,out} are redirected to files.
-  Try<MesosContainerizer*> _containerizer =
-    MesosContainerizer::create(flags, false, &fetcher);
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
 
-  ASSERT_SOME(_containerizer);
-  Owned<MesosContainerizer> containerizer(_containerizer.get());
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
@@ -788,8 +795,10 @@ TEST_F(MesosContainerizerDestroyTest, DestroyUnknownContainer)
 
   Fetcher fetcher;
 
-  Try<MesosContainerizer*> create =
-    MesosContainerizer::create(flags, true, &fetcher);
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      true,
+      &fetcher);
 
   ASSERT_SOME(create);
 
@@ -1218,11 +1227,14 @@ TEST_F(MesosContainerizerRecoverTest, SkipRecoverNonMesosContainers)
   slave::Flags flags = CreateSlaveFlags();
   Fetcher fetcher;
 
-  Try<MesosContainerizer*> _containerizer =
-    MesosContainerizer::create(flags, true, &fetcher);
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      true,
+      &fetcher);
 
-  ASSERT_SOME(_containerizer);
-  Owned<MesosContainerizer> containerizer(_containerizer.get());
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
 
   ExecutorID executorId;
   executorId.set_value(UUID::random().toString());
@@ -1314,12 +1326,14 @@ TEST_F(MesosContainerizerWaitTest, WaitUnknownContainer)
 
   Fetcher fetcher;
 
-  Try<MesosContainerizer*> create =
-    MesosContainerizer::create(flags, true, &fetcher);
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      true,
+      &fetcher);
 
   ASSERT_SOME(create);
 
-  MesosContainerizer* containerizer = create.get();
+  Owned<MesosContainerizer> containerizer(create.get());
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());


[4/4] mesos git commit: Refactored some test create* functions.

Posted by be...@apache.org.
Refactored some test create* functions.

Review: https://reviews.apache.org/r/52472


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/a450d829
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/a450d829
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/a450d829

Branch: refs/heads/master
Commit: a450d82934b459f1272d8de1a16e955c7d94e116
Parents: bb397f4
Author: Benjamin Hindman <be...@gmail.com>
Authored: Sun Oct 2 17:30:10 2016 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Mon Oct 3 19:20:26 2016 -0700

----------------------------------------------------------------------
 .../containerizer/filesystem_isolator_tests.cpp | 58 +++++------------
 src/tests/containerizer/isolator_tests.cpp      |  6 +-
 .../containerizer/mesos_containerizer_tests.cpp | 22 +++----
 .../volume_sandbox_path_isolator_tests.cpp      |  7 +-
 src/tests/gc_tests.cpp                          |  4 +-
 src/tests/hook_tests.cpp                        |  5 +-
 src/tests/master_allocator_tests.cpp            |  4 +-
 src/tests/master_authorization_tests.cpp        | 10 +--
 src/tests/master_maintenance_tests.cpp          |  4 +-
 src/tests/master_tests.cpp                      |  4 +-
 src/tests/mesos.hpp                             | 68 ++++++++++++++------
 src/tests/slave_authorization_tests.cpp         |  2 +-
 12 files changed, 98 insertions(+), 96 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/containerizer/filesystem_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/filesystem_isolator_tests.cpp b/src/tests/containerizer/filesystem_isolator_tests.cpp
index 3b34b8c..5b6a1d4 100644
--- a/src/tests/containerizer/filesystem_isolator_tests.cpp
+++ b/src/tests/containerizer/filesystem_isolator_tests.cpp
@@ -218,32 +218,6 @@ protected:
     return info;
   }
 
-  Volume createVolumeFromHostPath(
-      const string& containerPath,
-      const string& hostPath,
-      const Volume::Mode& mode)
-  {
-    return CREATE_VOLUME(containerPath, hostPath, mode);
-  }
-
-  Volume createVolumeFromImage(
-      const string& containerPath,
-      const string& imageName,
-      const Volume::Mode& mode)
-  {
-    Volume volume;
-    volume.set_container_path(containerPath);
-    volume.set_mode(mode);
-
-    Image* image = volume.mutable_image();
-    image->set_type(Image::APPC);
-
-    Image::Appc* appc = image->mutable_appc();
-    appc->set_name(imageName);
-
-    return volume;
-  }
-
 private:
   Fetcher fetcher;
 };
@@ -264,7 +238,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_ChangeRootFilesystem)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "[ ! -d '" + os::getcwd() + "' ]");
 
@@ -781,7 +755,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_Metrics)
   ASSERT_SOME(containerizer);
 
   // Use a long running task so we can reliably capture the moment it's alive.
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "sleep 1000");
 
@@ -842,7 +816,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_VolumeFromSandbox)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "echo abc > /tmp/file");
 
@@ -898,7 +872,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_VolumeFromHost)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "test -d /tmp/sandbox");
 
@@ -952,7 +926,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_FileVolumeFromHost)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "test -f /tmp/test/file.txt");
 
@@ -1006,7 +980,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_VolumeFromHostSandboxMountPoint)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "test -d mountpoint/sandbox");
 
@@ -1060,7 +1034,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_FileVolumeFromHostSandboxMountPoint)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "test -f mountpoint/file.txt");
 
@@ -1117,7 +1091,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_PersistentVolumeWithRootFilesystem)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "echo abc > volume/file");
 
@@ -1186,7 +1160,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_PersistentVolumeWithoutRootFilesystem)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "echo abc > volume/file");
 
@@ -1260,13 +1234,13 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_ImageInVolumeWithoutRootFilesystem)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "test -d rootfs/bin");
 
   executor.mutable_container()->CopyFrom(createContainerInfo(
       None(),
-      {createVolumeFromImage("rootfs", "test_image", Volume::RW)}));
+      {createVolumeFromAppcImage("rootfs", "test_image", Volume::RW)}));
 
   string directory = path::join(os::getcwd(), "sandbox");
   ASSERT_SOME(os::mkdir(directory));
@@ -1316,13 +1290,13 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_ImageInVolumeWithRootFilesystem)
 
   ASSERT_SOME(containerizer);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       "[ ! -d '" + os::getcwd() + "' ] && [ -d rootfs/bin ]");
 
   executor.mutable_container()->CopyFrom(createContainerInfo(
       "test_image_rootfs",
-      {createVolumeFromImage("rootfs", "test_image_volume", Volume::RW)}));
+      {createVolumeFromAppcImage("rootfs", "test_image_volume", Volume::RW)}));
 
   string directory = path::join(os::getcwd(), "sandbox");
   ASSERT_SOME(os::mkdir(directory));
@@ -1385,7 +1359,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_MultipleContainers)
   // First launch container 1 which has a long running task which
   // guarantees that its work directory mount is in the host mount
   // table when container 2 is launched.
-  ExecutorInfo executor1 = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor1 = createExecutorInfo(
       "test_executor1",
       "sleep 1000"); // Long running task.
 
@@ -1429,7 +1403,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_MultipleContainers)
 
   // Now launch container 2 which will copy the host mount table with
   // container 1's work directory mount in it.
-  ExecutorInfo executor2 = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor2 = createExecutorInfo(
       "test_executor2",
       "[ ! -d '" + os::getcwd() + "' ]");
 
@@ -1506,7 +1480,7 @@ TEST_F(LinuxFilesystemIsolatorTest, ROOT_SandboxEnvironmentVariable)
 
   ASSERT_SOME(script);
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO(
+  ExecutorInfo executor = createExecutorInfo(
       "test_executor",
       script.get());
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/containerizer/isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/isolator_tests.cpp b/src/tests/containerizer/isolator_tests.cpp
index 9458e7e..8fefeef 100644
--- a/src/tests/containerizer/isolator_tests.cpp
+++ b/src/tests/containerizer/isolator_tests.cpp
@@ -134,7 +134,7 @@ TEST_F(SharedFilesystemIsolatorTest, DISABLED_ROOT_RelativeVolume)
   ContainerInfo containerInfo;
   containerInfo.set_type(ContainerInfo::MESOS);
   containerInfo.add_volumes()->CopyFrom(
-      CREATE_VOLUME(containerPath, hostPath, Volume::RW));
+      createVolumeFromHostPath(containerPath, hostPath, Volume::RW));
 
   ExecutorInfo executorInfo;
   executorInfo.mutable_container()->CopyFrom(containerInfo);
@@ -240,7 +240,7 @@ TEST_F(SharedFilesystemIsolatorTest, DISABLED_ROOT_AbsoluteVolume)
   ContainerInfo containerInfo;
   containerInfo.set_type(ContainerInfo::MESOS);
   containerInfo.add_volumes()->CopyFrom(
-      CREATE_VOLUME(containerPath, hostPath, Volume::RW));
+      createVolumeFromHostPath(containerPath, hostPath, Volume::RW));
 
   ExecutorInfo executorInfo;
   executorInfo.mutable_container()->CopyFrom(containerInfo);
@@ -329,7 +329,7 @@ TEST_F(NamespacesPidIsolatorTest, ROOT_PidNamespace)
   process::Future<bool> launch = containerizer->launch(
       containerId,
       None(),
-      CREATE_EXECUTOR_INFO("executor", command),
+      createExecutorInfo("executor", command),
       directory,
       None(),
       SlaveID(),

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/containerizer/mesos_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/mesos_containerizer_tests.cpp b/src/tests/containerizer/mesos_containerizer_tests.cpp
index 8b5a19e..44093ce 100644
--- a/src/tests/containerizer/mesos_containerizer_tests.cpp
+++ b/src/tests/containerizer/mesos_containerizer_tests.cpp
@@ -204,7 +204,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ScriptSucceeds)
   Future<bool> launch = containerizer.get()->launch(
       containerId,
       None(),
-      CREATE_EXECUTOR_INFO("executor", "exit 0"),
+      createExecutorInfo("executor", "exit 0"),
       directory,
       None(),
       SlaveID(),
@@ -257,7 +257,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ScriptFails)
   Future<bool> launch = containerizer.get()->launch(
       containerId,
       None(),
-      CREATE_EXECUTOR_INFO("executor", "exit 0"),
+      createExecutorInfo("executor", "exit 0"),
       directory,
       None(),
       SlaveID(),
@@ -321,7 +321,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, MultipleScripts)
   Future<bool> launch = containerizer.get()->launch(
       containerId,
       None(),
-      CREATE_EXECUTOR_INFO("executor", "exit 0"),
+      createExecutorInfo("executor", "exit 0"),
       directory,
       None(),
       SlaveID(),
@@ -389,7 +389,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ExecutorEnvironmentVariable)
     "if [ -n \"$LIBPROCESS_IP\" ]; "
     "then touch $TEST_ENVIRONMENT; fi";
 
-  ExecutorInfo executorInfo = CREATE_EXECUTOR_INFO("executor", executorCmd);
+  ExecutorInfo executorInfo = createExecutorInfo("executor", executorCmd);
   SlaveID slaveId = SlaveID();
 
   slave::Flags flags;
@@ -470,7 +470,7 @@ TEST_F(MesosContainerizerExecuteTest, IoRedirection)
   Future<bool> launch = containerizer->launch(
       containerId,
       None(),
-      CREATE_EXECUTOR_INFO("executor", command),
+      createExecutorInfo("executor", command),
       directory,
       None(),
       SlaveID(),
@@ -659,7 +659,7 @@ TEST_F(MesosContainerizerDestroyTest, DestroyWhileFetching)
   containerizer.launch(
       containerId,
       taskInfo,
-      CREATE_EXECUTOR_INFO("executor", "exit 0"),
+      createExecutorInfo("executor", "exit 0"),
       os::getcwd(),
       None(),
       SlaveID(),
@@ -730,7 +730,7 @@ TEST_F(MesosContainerizerDestroyTest, DestroyWhilePreparing)
   containerizer.launch(
       containerId,
       taskInfo,
-      CREATE_EXECUTOR_INFO("executor", "exit 0"),
+      createExecutorInfo("executor", "exit 0"),
       os::getcwd(),
       None(),
       SlaveID(),
@@ -866,7 +866,7 @@ TEST_F(MesosContainerizerProvisionerTest, ProvisionFailed)
   taskInfo.mutable_command()->MergeFrom(commandInfo);
   taskInfo.mutable_container()->CopyFrom(containerInfo);
 
-  ExecutorInfo executorInfo = CREATE_EXECUTOR_INFO("executor", "exit 0");
+  ExecutorInfo executorInfo = createExecutorInfo("executor", "exit 0");
   executorInfo.mutable_container()->CopyFrom(containerInfo);
 
   Future<bool> launch = containerizer.launch(
@@ -961,7 +961,7 @@ TEST_F(MesosContainerizerProvisionerTest, DestroyWhileProvisioning)
   taskInfo.mutable_command()->MergeFrom(commandInfo);
   taskInfo.mutable_container()->CopyFrom(containerInfo);
 
-  ExecutorInfo executorInfo = CREATE_EXECUTOR_INFO("executor", "exit 0");
+  ExecutorInfo executorInfo = createExecutorInfo("executor", "exit 0");
   executorInfo.mutable_container()->CopyFrom(containerInfo);
 
   Future<bool> launch = containerizer.launch(
@@ -1063,7 +1063,7 @@ TEST_F(MesosContainerizerProvisionerTest, IsolatorCleanupBeforePrepare)
   taskInfo.mutable_command()->MergeFrom(commandInfo);
   taskInfo.mutable_container()->CopyFrom(containerInfo);
 
-  ExecutorInfo executorInfo = CREATE_EXECUTOR_INFO("executor", "exit 0");
+  ExecutorInfo executorInfo = createExecutorInfo("executor", "exit 0");
   executorInfo.mutable_container()->CopyFrom(containerInfo);
 
   Future<bool> launch = containerizer.launch(
@@ -1155,7 +1155,7 @@ TEST_F(MesosContainerizerDestroyTest, LauncherDestroyFailure)
   Future<bool> launch = containerizer.launch(
       containerId,
       taskInfo,
-      CREATE_EXECUTOR_INFO("executor", "sleep 1000"),
+      createExecutorInfo("executor", "sleep 1000"),
       os::getcwd(),
       None(),
       SlaveID(),

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/containerizer/volume_sandbox_path_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/volume_sandbox_path_isolator_tests.cpp b/src/tests/containerizer/volume_sandbox_path_isolator_tests.cpp
index d4f074a..f873e28 100644
--- a/src/tests/containerizer/volume_sandbox_path_isolator_tests.cpp
+++ b/src/tests/containerizer/volume_sandbox_path_isolator_tests.cpp
@@ -69,8 +69,7 @@ TEST_F(VolumeSandboxPathIsolatorTest, SharedVolume)
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
 
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO("executor", "sleep 1000");
-  executor.mutable_resources()->CopyFrom(Resources::parse("cpus:1").get());
+  ExecutorInfo executor = createExecutorInfo("executor", "sleep 99", "cpus:1");
 
   Try<string> directory = environment->mkdtemp();
   ASSERT_SOME(directory);
@@ -107,7 +106,7 @@ TEST_F(VolumeSandboxPathIsolatorTest, SharedVolume)
 
   launch = containerizer->launch(
       nestedContainerId1,
-      CREATE_COMMAND_INFO("touch parent/file; sleep 1000"),
+      createCommandInfo("touch parent/file; sleep 1000"),
       containerInfo,
       None(),
       state.id);
@@ -120,7 +119,7 @@ TEST_F(VolumeSandboxPathIsolatorTest, SharedVolume)
 
   launch = containerizer->launch(
       nestedContainerId2,
-      CREATE_COMMAND_INFO(
+      createCommandInfo(
         "while true; do if [ -f parent/file ]; then exit 0; fi; done"),
       containerInfo,
       None(),

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/gc_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/gc_tests.cpp b/src/tests/gc_tests.cpp
index f3aec4a..d9776b6 100644
--- a/src/tests/gc_tests.cpp
+++ b/src/tests/gc_tests.cpp
@@ -735,8 +735,8 @@ TEST_F(GarbageCollectorIntegrationTest, Unschedule)
   Future<SlaveRegisteredMessage> slaveRegistered =
     FUTURE_PROTOBUF(SlaveRegisteredMessage(), _, _);
 
-  ExecutorInfo executor1 = CREATE_EXECUTOR_INFO("executor-1", "exit 1");
-  ExecutorInfo executor2 = CREATE_EXECUTOR_INFO("executor-2", "exit 1");
+  ExecutorInfo executor1 = createExecutorInfo("executor-1", "exit 1");
+  ExecutorInfo executor2 = createExecutorInfo("executor-2", "exit 1");
 
   MockExecutor exec1(executor1.executor_id());
   MockExecutor exec2(executor2.executor_id());

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/hook_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/hook_tests.cpp b/src/tests/hook_tests.cpp
index f837ca7..d334d6c 100644
--- a/src/tests/hook_tests.cpp
+++ b/src/tests/hook_tests.cpp
@@ -294,8 +294,9 @@ TEST_F(HookTest, VerifySlaveExecutorEnvironmentDecorator)
   ContainerID containerId;
   containerId.set_value("test_container");
 
-  ExecutorInfo executorInfo =
-    CREATE_EXECUTOR_INFO("executor", "test $FOO = 'bar'");
+  ExecutorInfo executorInfo = createExecutorInfo(
+      "executor",
+      "test $FOO = 'bar'");
 
   SlaveID slaveId = SlaveID();
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/master_allocator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_allocator_tests.cpp b/src/tests/master_allocator_tests.cpp
index b4ecd46..bb94e38 100644
--- a/src/tests/master_allocator_tests.cpp
+++ b/src/tests/master_allocator_tests.cpp
@@ -572,8 +572,8 @@ TYPED_TEST(MasterAllocatorTest, FrameworkExited)
     this->StartMaster(&allocator, masterFlags);
   ASSERT_SOME(master);
 
-  ExecutorInfo executor1 = CREATE_EXECUTOR_INFO("executor-1", "exit 1");
-  ExecutorInfo executor2 = CREATE_EXECUTOR_INFO("executor-2", "exit 1");
+  ExecutorInfo executor1 = createExecutorInfo("executor-1", "exit 1");
+  ExecutorInfo executor2 = createExecutorInfo("executor-2", "exit 1");
 
   MockExecutor exec1(executor1.executor_id());
   MockExecutor exec2(executor2.executor_id());

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/master_authorization_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_authorization_tests.cpp b/src/tests/master_authorization_tests.cpp
index 5d08ebc..a4623d1 100644
--- a/src/tests/master_authorization_tests.cpp
+++ b/src/tests/master_authorization_tests.cpp
@@ -108,7 +108,7 @@ TEST_F(MasterAuthorizationTest, AuthorizedTask)
   ASSERT_SOME(master);
 
   // Create an authorized executor.
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO("test-executor", "exit 1");
+  ExecutorInfo executor = createExecutorInfo("test-executor", "exit 1");
   executor.mutable_command()->set_user("foo");
 
   MockExecutor exec(executor.executor_id());
@@ -182,7 +182,7 @@ TEST_F(MasterAuthorizationTest, UnauthorizedTask)
   ASSERT_SOME(master);
 
   // Create an unauthorized executor.
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO("test-executor", "exit 1");
+  ExecutorInfo executor = createExecutorInfo("test-executor", "exit 1");
   executor.mutable_command()->set_user("foo");
 
   MockExecutor exec(executor.executor_id());
@@ -1498,7 +1498,7 @@ TYPED_TEST(MasterAuthorizerTest, FilterStateEndpoint)
   frameworkInfo.set_user(user);
 
   // Create an executor with user "bar".
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO("test-executor", "sleep 2");
+  ExecutorInfo executor = createExecutorInfo("test-executor", "sleep 2");
   executor.mutable_command()->set_user(user);
 
   MockExecutor exec(executor.executor_id());
@@ -1687,7 +1687,7 @@ TYPED_TEST(MasterAuthorizerTest, FilterFrameworksEndpoint)
   frameworkInfo.set_user("bar");
 
   // Create an executor with user "bar".
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO("test-executor", "sleep 2");
+  ExecutorInfo executor = createExecutorInfo("test-executor", "sleep 2");
   executor.mutable_command()->set_user("bar");
 
   MockExecutor exec(executor.executor_id());
@@ -1878,7 +1878,7 @@ TYPED_TEST(MasterAuthorizerTest, FilterTasksEndpoint)
   frameworkInfo.set_user(user);
 
   // Create an executor with user "bar".
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO("test-executor", "sleep 2");
+  ExecutorInfo executor = createExecutorInfo("test-executor", "sleep 2");
   executor.mutable_command()->set_user(user);
 
   MockExecutor exec(executor.executor_id());

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/master_maintenance_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_maintenance_tests.cpp b/src/tests/master_maintenance_tests.cpp
index 0820e63..77eb405 100644
--- a/src/tests/master_maintenance_tests.cpp
+++ b/src/tests/master_maintenance_tests.cpp
@@ -1394,8 +1394,8 @@ TEST_F(MasterMaintenanceTest, InverseOffersFilters)
   Try<Owned<cluster::Master>> master = StartMaster(flags);
   ASSERT_SOME(master);
 
-  ExecutorInfo executor1 = CREATE_EXECUTOR_INFO("executor-1", "exit 1");
-  ExecutorInfo executor2 = CREATE_EXECUTOR_INFO("executor-2", "exit 2");
+  ExecutorInfo executor1 = createExecutorInfo("executor-1", "exit 1");
+  ExecutorInfo executor2 = createExecutorInfo("executor-2", "exit 2");
 
   MockExecutor exec1(executor1.executor_id());
   MockExecutor exec2(executor2.executor_id());

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index e6c8362..88cf1e6 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -1004,8 +1004,8 @@ TEST_F(MasterTest, MultipleExecutors)
   Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
-  ExecutorInfo executor1 = CREATE_EXECUTOR_INFO("executor-1", "exit 1");
-  ExecutorInfo executor2 = CREATE_EXECUTOR_INFO("executor-2", "exit 1");
+  ExecutorInfo executor1 = createExecutorInfo("executor-1", "exit 1");
+  ExecutorInfo executor2 = createExecutorInfo("executor-2", "exit 1");
 
   MockExecutor exec1(executor1.executor_id());
   MockExecutor exec2(executor2.executor_id());

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/mesos.hpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.hpp b/src/tests/mesos.hpp
index 3876a08..a05e3e0 100644
--- a/src/tests/mesos.hpp
+++ b/src/tests/mesos.hpp
@@ -346,13 +346,6 @@ protected:
         executor; })
 
 
-#define CREATE_EXECUTOR_INFO(executorId, command)                       \
-      ({ ExecutorInfo executor;                                         \
-        executor.mutable_executor_id()->set_value(executorId);          \
-        executor.mutable_command()->set_value(command);                 \
-        executor; })
-
-
 #define DEFAULT_CREDENTIAL                                             \
      ({ Credential credential;                                         \
         credential.set_principal("test-principal");                    \
@@ -404,20 +397,55 @@ protected:
         containerId; })
 
 
-#define CREATE_COMMAND_INFO(command)                                  \
-  ({ CommandInfo commandInfo;                                         \
-     commandInfo.set_value(command);                                  \
-     commandInfo; })
+inline ExecutorInfo createExecutorInfo(
+    const std::string& executorId,
+    const std::string& command,
+    const Option<std::string>& resources = None())
+{
+  ExecutorInfo executor;
+  executor.mutable_executor_id()->set_value(executorId);
+  executor.mutable_command()->set_value(command);
+  if (resources.isSome()) {
+    executor.mutable_resources()->CopyFrom(
+        Resources::parse(resources.get()).get());
+  }
+  return executor;
+}
+
+
+inline CommandInfo createCommandInfo(const std::string& command)
+{
+  CommandInfo commandInfo;
+  commandInfo.set_value(command);
+  return commandInfo;
+}
+
 
+inline Volume createVolumeFromHostPath(
+    const std::string& containerPath,
+    const std::string& hostPath,
+    const Volume::Mode& mode)
+{
+  Volume volume;
+  volume.set_container_path(containerPath);
+  volume.set_host_path(hostPath);
+  volume.set_mode(mode);
+  return volume;
+}
 
-// TODO(jieyu): Consider making it a function to support more
-// overloads (e.g., createVolumeFromHost, createVolumeFromImage).
-#define CREATE_VOLUME(containerPath, hostPath, mode)                  \
-      ({ Volume volume;                                               \
-         volume.set_container_path(containerPath);                    \
-         volume.set_host_path(hostPath);                              \
-         volume.set_mode(mode);                                       \
-         volume; })
+
+inline Volume createVolumeFromAppcImage(
+    const std::string& containerPath,
+    const std::string& imageName,
+    const Volume::Mode& mode)
+{
+  Volume volume;
+  volume.set_container_path(containerPath);
+  volume.set_mode(mode);
+  volume.mutable_image()->set_type(Image::APPC);
+  volume.mutable_image()->mutable_appc()->set_name(imageName);
+  return volume;
+}
 
 
 // TODO(bmahler): Refactor this to make the distinction between
@@ -459,7 +487,7 @@ inline TaskInfo createTask(
   return createTask(
       slaveId,
       resources,
-      CREATE_COMMAND_INFO(command),
+      createCommandInfo(command),
       executorId,
       name,
       id);

http://git-wip-us.apache.org/repos/asf/mesos/blob/a450d829/src/tests/slave_authorization_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_authorization_tests.cpp b/src/tests/slave_authorization_tests.cpp
index 20bb712..6bd2aa9 100644
--- a/src/tests/slave_authorization_tests.cpp
+++ b/src/tests/slave_authorization_tests.cpp
@@ -148,7 +148,7 @@ TYPED_TEST(SlaveAuthorizerTest, FilterStateEndpoint)
   frameworkInfo.set_user("bar");
 
   // Create an executor with user "bar".
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO("test-executor", "sleep 2");
+  ExecutorInfo executor = createExecutorInfo("test-executor", "sleep 2");
   executor.mutable_command()->set_user("bar");
 
   MockExecutor exec(executor.executor_id());


[2/4] mesos git commit: Added nested MesosContainerizer tests.

Posted by be...@apache.org.
Added nested MesosContainerizer tests.

Review: https://reviews.apache.org/r/52473


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/66d4b269
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/66d4b269
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/66d4b269

Branch: refs/heads/master
Commit: 66d4b269733d7936e4c30784e81a5a6847a01baa
Parents: a450d82
Author: Benjamin Hindman <be...@gmail.com>
Authored: Sun Sep 18 15:33:47 2016 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Mon Oct 3 19:20:26 2016 -0700

----------------------------------------------------------------------
 src/Makefile.am                                 |    2 +-
 .../containerizer/mesos_containerizer_tests.cpp |  115 +-
 .../containerizer/nested_container_tests.cpp    |  144 --
 .../nested_mesos_containerizer_tests.cpp        | 1438 ++++++++++++++++++
 4 files changed, 1536 insertions(+), 163 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/66d4b269/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index c897d86..184afb5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2163,7 +2163,6 @@ mesos_tests_SOURCES =						\
   tests/containerizer/memory_test_helper.cpp			\
   tests/containerizer/mesos_containerizer_tests.cpp		\
   tests/containerizer/mesos_containerizer_paths_tests.cpp	\
-  tests/containerizer/nested_container_tests.cpp		\
   tests/containerizer/provisioner_appc_tests.cpp		\
   tests/containerizer/provisioner_backend_tests.cpp		\
   tests/containerizer/provisioner_docker_tests.cpp		\
@@ -2212,6 +2211,7 @@ mesos_tests_SOURCES +=						\
   tests/containerizer/fs_tests.cpp				\
   tests/containerizer/launch_tests.cpp				\
   tests/containerizer/memory_pressure_tests.cpp			\
+  tests/containerizer/nested_mesos_containerizer_tests.cpp	\
   tests/containerizer/ns_tests.cpp				\
   tests/containerizer/nvidia_gpu_isolator_tests.cpp		\
   tests/containerizer/perf_tests.cpp				\

http://git-wip-us.apache.org/repos/asf/mesos/blob/66d4b269/src/tests/containerizer/mesos_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/mesos_containerizer_tests.cpp b/src/tests/containerizer/mesos_containerizer_tests.cpp
index 44093ce..f64ec5d 100644
--- a/src/tests/containerizer/mesos_containerizer_tests.cpp
+++ b/src/tests/containerizer/mesos_containerizer_tests.cpp
@@ -44,6 +44,7 @@
 
 #include "slave/containerizer/mesos/provisioner/provisioner.hpp"
 
+#include "tests/environment.hpp"
 #include "tests/flags.hpp"
 #include "tests/mesos.hpp"
 #include "tests/utils.hpp"
@@ -92,30 +93,108 @@ namespace mesos {
 namespace internal {
 namespace tests {
 
-TEST(MesosContainerizerTest, NestedContainerID)
+class MesosContainerizerTest
+  : public ContainerizerTest<slave::MesosContainerizer> {};
+
+
+// TODO(benh): Parameterize this test by each `Launcher`.
+TEST_F(MesosContainerizerTest, Launch)
 {
-  ContainerID id1;
-  id1.set_value(UUID::random().toString());
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "posix";
+  flags.isolation = "posix/cpu";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      true,
+      &fetcher);
+
+  ASSERT_SOME(create);
 
-  ContainerID id2;
-  id2.set_value(UUID::random().toString());
+  Owned<MesosContainerizer> containerizer(create.get());
 
-  EXPECT_EQ(id1, id1);
-  EXPECT_NE(id1, id2);
+  SlaveState state;
+  state.id = SlaveID();
 
-  ContainerID id3 = id1;
-  id3.mutable_parent()->CopyFrom(id2);
+  AWAIT_READY(containerizer->recover(state));
 
-  EXPECT_EQ(id3, id3);
-  EXPECT_NE(id3, id1);
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
 
-  hashset<ContainerID> ids;
-  ids.insert(id2);
-  ids.insert(id3);
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
 
-  EXPECT_TRUE(ids.contains(id2));
-  EXPECT_TRUE(ids.contains(id3));
-  EXPECT_FALSE(ids.contains(id1));
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      createExecutorInfo("executor", "exit 42", "cpus:1"),
+      directory.get(),
+      None(),
+      SlaveID(),
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WEXITSTATUS_EQ(42, wait.get()->status());
+}
+
+
+TEST_F(MesosContainerizerTest, Destroy)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "posix";
+  flags.isolation = "posix/cpu";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      true,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      createExecutorInfo("executor", "sleep 1000", "cpus:1"),
+      directory.get(),
+      None(),
+      SlaveID(),
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+
+  containerizer->destroy(containerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
 }
 
 
@@ -368,7 +447,7 @@ TEST_F(MesosContainerizerIsolatorPreparationTest, ExecutorEnvironmentVariable)
 
   ContainerLaunchInfo launchInfo;
 
-  Environment::Variable* variable =
+  mesos::Environment::Variable* variable =
     launchInfo.mutable_environment()->add_variables();
 
   variable->set_name("TEST_ENVIRONMENT");

http://git-wip-us.apache.org/repos/asf/mesos/blob/66d4b269/src/tests/containerizer/nested_container_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/nested_container_tests.cpp b/src/tests/containerizer/nested_container_tests.cpp
deleted file mode 100644
index 8430823..0000000
--- a/src/tests/containerizer/nested_container_tests.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-// 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.
-
-#include <string>
-
-#include <stout/gtest.hpp>
-#include <stout/none.hpp>
-#include <stout/option.hpp>
-#include <stout/try.hpp>
-
-#include <process/future.hpp>
-#include <process/gtest.hpp>
-
-#include "slave/containerizer/mesos/containerizer.hpp"
-
-#include "tests/environment.hpp"
-#include "tests/mesos.hpp"
-
-using mesos::internal::slave::Fetcher;
-using mesos::internal::slave::MesosContainerizer;
-using mesos::internal::slave::MesosContainerizerProcess;
-
-using mesos::internal::slave::state::SlaveState;
-
-using mesos::slave::ContainerTermination;
-
-using process::Future;
-using process::Owned;
-
-using std::string;
-
-namespace mesos {
-namespace internal {
-namespace tests {
-
-class NestedContainerTest : public ContainerizerTest<MesosContainerizer> {};
-
-
-TEST_F(NestedContainerTest, ROOT_CGROUPS_WaitAfterDestroy)
-{
-  slave::Flags flags = CreateSlaveFlags();
-  flags.launcher = "linux";
-  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
-
-  Fetcher fetcher;
-
-  Try<MesosContainerizer*> create = MesosContainerizer::create(
-      flags,
-      true,
-      &fetcher);
-
-  ASSERT_SOME(create);
-
-  Owned<MesosContainerizer> containerizer(create.get());
-
-  SlaveID slaveId = SlaveID();
-
-  // Launch a top-level container.
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  ExecutorInfo executor = CREATE_EXECUTOR_INFO("executor", "sleep 1000");
-  executor.mutable_resources()->CopyFrom(Resources::parse("cpus:1").get());
-
-  Try<string> directory = environment->mkdtemp();
-  ASSERT_SOME(directory);
-
-  Future<bool> launch = containerizer->launch(
-      containerId,
-      None(),
-      executor,
-      directory.get(),
-      None(),
-      slaveId,
-      map<string, string>(),
-      true);
-
-  AWAIT_ASSERT_TRUE(launch);
-
-  // Launch a nested container.
-  ContainerID nestedContainerId;
-  nestedContainerId.mutable_parent()->CopyFrom(containerId);
-  nestedContainerId.set_value(UUID::random().toString());
-
-  launch = containerizer->launch(
-      nestedContainerId,
-      CREATE_COMMAND_INFO("exit 42"),
-      None(),
-      None(),
-      slaveId);
-
-  AWAIT_ASSERT_TRUE(launch);
-
-  // Wait once (which does a destroy),
-  // then wait again on the nested container.
-  Future<Option<ContainerTermination>> nestedWait =
-    containerizer->wait(nestedContainerId);
-
-  AWAIT_READY(nestedWait);
-  ASSERT_SOME(nestedWait.get());
-  ASSERT_TRUE(nestedWait.get()->has_status());
-  EXPECT_WEXITSTATUS_EQ(42, nestedWait.get()->status());
-
-  nestedWait = containerizer->wait(nestedContainerId);
-
-  AWAIT_READY(nestedWait);
-  ASSERT_SOME(nestedWait.get());
-  ASSERT_TRUE(nestedWait.get()->has_status());
-  EXPECT_WEXITSTATUS_EQ(42, nestedWait.get()->status());
-
-  // Destroy the top-level container.
-  Future<Option<ContainerTermination>> wait =
-    containerizer->wait(containerId);
-
-  AWAIT_READY(containerizer->destroy(containerId));
-
-  AWAIT_READY(wait);
-  ASSERT_SOME(wait.get());
-  ASSERT_TRUE(wait.get()->has_status());
-  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
-
-  // Wait on nested container again.
-  nestedWait = containerizer->wait(nestedContainerId);
-
-  AWAIT_READY(nestedWait);
-  ASSERT_NONE(nestedWait.get());
-}
-
-} // namespace tests {
-} // namespace internal {
-} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/66d4b269/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/nested_mesos_containerizer_tests.cpp b/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
new file mode 100644
index 0000000..9b278e5
--- /dev/null
+++ b/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
@@ -0,0 +1,1438 @@
+// 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.
+
+#include <sys/wait.h>
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <gmock/gmock.h>
+
+#include <stout/gtest.hpp>
+#include <stout/none.hpp>
+#include <stout/option.hpp>
+#include <stout/os.hpp>
+#include <stout/try.hpp>
+
+#include <stout/os/kill.hpp>
+
+#include <process/future.hpp>
+#include <process/gtest.hpp>
+#include <process/io.hpp>
+#include <process/owned.hpp>
+
+#include "linux/cgroups.hpp"
+#include "linux/ns.hpp"
+
+#include "slave/containerizer/mesos/launch.hpp"
+#include "slave/containerizer/mesos/linux_launcher.hpp"
+#include "slave/containerizer/mesos/paths.hpp"
+
+#include "tests/environment.hpp"
+#include "tests/mesos.hpp"
+
+using mesos::internal::slave::Fetcher;
+using mesos::internal::slave::MesosContainerizer;
+
+using mesos::internal::slave::containerizer::paths::buildPath;
+using mesos::internal::slave::containerizer::paths::JOIN;
+using mesos::internal::slave::containerizer::paths::PREFIX;
+using mesos::internal::slave::containerizer::paths::SUFFIX;
+
+using mesos::internal::slave::state::ExecutorState;
+using mesos::internal::slave::state::FrameworkState;
+using mesos::internal::slave::state::RunState;
+using mesos::internal::slave::state::SlaveState;
+
+using mesos::slave::ContainerState;
+using mesos::slave::ContainerTermination;
+
+using process::Future;
+using process::Owned;
+
+using std::ostringstream;
+using std::string;
+using std::vector;
+
+namespace mesos {
+namespace internal {
+namespace tests {
+
+class NestedMesosContainerizerTest
+  : public ContainerizerTest<slave::MesosContainerizer>
+{
+protected:
+  Try<SlaveState> createSlaveState(
+      const ContainerID& containerId,
+      const pid_t pid,
+      const ExecutorInfo& executorInfo,
+      const SlaveID& slaveId,
+      const string& workDir)
+  {
+    // Construct a mock `SlaveState`.
+    ExecutorState executorState;
+    executorState.id = executorInfo.executor_id();
+    executorState.info = executorInfo;
+    executorState.latest = containerId;
+
+    RunState runState;
+    runState.id = containerId;
+    runState.forkedPid = pid;
+    executorState.runs.put(containerId, runState);
+
+    FrameworkState frameworkState;
+    frameworkState.executors.put(executorInfo.executor_id(), executorState);
+
+    SlaveState slaveState;
+    slaveState.id = slaveId;
+    FrameworkID frameworkId;
+    frameworkId.set_value(UUID::random().toString());
+    slaveState.frameworks.put(frameworkId, frameworkState);
+
+    // NOTE: The executor directory must exist for executor containers
+    // otherwise when the containerizer recovers from the 'SlaveState'
+    // it will fail.
+    const string directory = slave::paths::getExecutorRunPath(
+        workDir,
+        slaveId,
+        frameworkState.id,
+        executorState.id,
+        containerId);
+
+    Try<Nothing> mkdir = os::mkdir(directory);
+    if (mkdir.isError()) {
+      return Error(
+          "Failed to create directory '" + directory + "': " + mkdir.error());
+    }
+
+    return slaveState;
+  }
+};
+
+
+TEST_F(NestedMesosContainerizerTest, NestedContainerID)
+{
+  ContainerID id1;
+  id1.set_value(UUID::random().toString());
+
+  ContainerID id2;
+  id2.set_value(UUID::random().toString());
+
+  EXPECT_EQ(id1, id1);
+  EXPECT_NE(id1, id2);
+
+  ContainerID id3 = id1;
+  id3.mutable_parent()->CopyFrom(id2);
+
+  EXPECT_EQ(id3, id3);
+  EXPECT_NE(id3, id1);
+
+  hashset<ContainerID> ids;
+  ids.insert(id2);
+  ids.insert(id3);
+
+  EXPECT_TRUE(ids.contains(id2));
+  EXPECT_TRUE(ids.contains(id3));
+  EXPECT_FALSE(ids.contains(id1));
+
+  ostringstream out1;
+  out1 << id1;
+  EXPECT_EQ(id1.value(), out1.str());
+
+  ostringstream out2;
+  out2 << id3;
+  EXPECT_EQ(strings::join(".", id2.value(), id3.value()), out2.str());
+}
+
+
+TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_LaunchNested)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      createExecutorInfo("executor", "sleep 1000", "cpus:1"),
+      directory.get(),
+      None(),
+      state.id,
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  // Now launch nested container.
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo("exit 42"),
+      None(),
+      None(),
+      state.id);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(
+      nestedContainerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WEXITSTATUS_EQ(42, wait.get()->status());
+
+  wait = containerizer->wait(containerId);
+
+  containerizer->destroy(containerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+}
+
+
+TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_DestroyNested)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      createExecutorInfo("executor", "sleep 1000", "cpus:1"),
+      directory.get(),
+      None(),
+      state.id,
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  // Now launch nested container.
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo("sleep 1000"),
+      None(),
+      None(),
+      state.id);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<Option<ContainerTermination>> nestedWait = containerizer->wait(
+      nestedContainerId);
+
+  containerizer->destroy(nestedContainerId);
+
+  AWAIT_READY(nestedWait);
+  ASSERT_SOME(nestedWait.get());
+
+  // We expect a wait status of SIGKILL on the nested container.
+  // Since the kernel will destroy these via a SIGKILL, we expect
+  // a SIGKILL here.
+  ASSERT_TRUE(nestedWait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, nestedWait.get()->status());
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+
+  containerizer->destroy(containerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+}
+
+
+TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_DestroyParent)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      createExecutorInfo("executor", "sleep 1000", "cpus:1"),
+      directory.get(),
+      None(),
+      state.id,
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  // Now launch nested container.
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo("sleep 1000"),
+      None(),
+      None(),
+      state.id);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+
+  Future<Option<ContainerTermination>> nestedWait = containerizer->wait(
+      nestedContainerId);
+
+  containerizer->destroy(containerId);
+
+  AWAIT_READY(nestedWait);
+  ASSERT_SOME(nestedWait.get());
+
+  // We expect a wait status of SIGKILL on the nested container.
+  // Since the kernel will destroy these via a SIGKILL, we expect
+  // a SIGKILL here.
+  ASSERT_TRUE(nestedWait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, nestedWait.get()->status());
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+}
+
+
+TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_ParentExit)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      true,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  int pipes[2] = {-1, -1};
+  ASSERT_SOME(os::pipe(pipes));
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      createExecutorInfo(
+          "executor",
+          "read key <&" + stringify(pipes[0]),
+          "cpus:1"),
+      directory.get(),
+      None(),
+      state.id,
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  close(pipes[0]); // We're never going to read.
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  // Now launch nested container.
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo("sleep 1000"),
+      None(),
+      None(),
+      state.id);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+
+  Future<Option<ContainerTermination>> nestedWait = containerizer->wait(
+      nestedContainerId);
+
+  close(pipes[1]); // Force the 'read key' to exit!
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WEXITSTATUS_NE(0, wait.get()->status());
+
+  AWAIT_READY(nestedWait);
+  ASSERT_SOME(nestedWait.get());
+
+  // We expect a wait status of SIGKILL on the nested container
+  // because when the parent container is destroyed we expect any
+  // nested containers to be destroyed as a result of destroying the
+  // parent's pid namespace. Since the kernel will destroy these via a
+  // SIGKILL, we expect a SIGKILL here.
+  ASSERT_TRUE(nestedWait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, nestedWait.get()->status());
+}
+
+
+TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_ParentSigterm)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  // Use a pipe to synchronize with the top-level container.
+  int pipes[2] = {-1, -1};
+  ASSERT_SOME(os::pipe(pipes));
+
+  // NOTE: We use a non-shell command here to use 'bash -c' to execute
+  // the 'echo', which deals with the file descriptor, because of a bug
+  // in ubuntu dash. Multi-digit file descriptor is not supported in
+  // ubuntu dash, which executes the shell command.
+  CommandInfo command;
+  command.set_shell(false);
+  command.set_value("/bin/bash");
+  command.add_arguments("bash");
+  command.add_arguments("-c");
+  command.add_arguments(
+      "echo running >&" + stringify(pipes[1]) + ";" + "sleep 1000");
+
+  ExecutorInfo executor;
+  executor.mutable_executor_id()->set_value("executor");
+  executor.mutable_command()->CopyFrom(command);
+  executor.mutable_resources()->CopyFrom(Resources::parse("cpus:1").get());
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      executor,
+      directory.get(),
+      None(),
+      state.id,
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  close(pipes[1]);
+
+  // Now launch nested container.
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo("sleep 1000"),
+      None(),
+      None(),
+      state.id);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+
+  Future<Option<ContainerTermination>> nestedWait = containerizer->wait(
+      nestedContainerId);
+
+  Future<ContainerStatus> status = containerizer->status(containerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+
+  // Wait for the parent container to start running its executor
+  // process before sending it a signal.
+  AWAIT_READY(process::io::poll(pipes[0], process::io::READ));
+  close(pipes[0]);
+
+  ASSERT_EQ(0u, os::kill(status->executor_pid(), SIGTERM));
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGTERM, wait.get()->status());
+
+  AWAIT_READY(nestedWait);
+  ASSERT_SOME(nestedWait.get());
+
+  // We expect a wait status of SIGKILL on the nested container
+  // because when the parent container is destroyed we expect any
+  // nested containers to be destroyed as a result of destroying the
+  // parent's pid namespace. Since the kernel will destroy these via a
+  // SIGKILL, we expect a SIGKILL here.
+  ASSERT_TRUE(nestedWait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, nestedWait.get()->status());
+}
+
+
+TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_RecoverNested)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  ExecutorInfo executor = createExecutorInfo(
+      "executor",
+      "sleep 1000",
+      "cpus:1");
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      executor,
+      directory.get(),
+      None(),
+      SlaveID(),
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<ContainerStatus> status = containerizer->status(containerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+
+  pid_t pid = status->executor_pid();
+
+  // Now launch nested container.
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo("sleep 1000"),
+      None(),
+      None(),
+      state.id);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  status = containerizer->status(nestedContainerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+
+  pid_t nestedPid = status->executor_pid();
+
+  // Force a delete on the containerizer before we create the new one.
+  containerizer.reset();
+
+  create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  containerizer.reset(create.get());
+
+  Try<SlaveState> slaveState = createSlaveState(
+      containerId,
+      pid,
+      executor,
+      state.id,
+      flags.work_dir);
+
+  ASSERT_SOME(slaveState);
+
+  state = slaveState.get();
+  AWAIT_READY(containerizer->recover(state));
+
+  status = containerizer->status(containerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+  EXPECT_EQ(pid, status->executor_pid());
+
+  status = containerizer->status(nestedContainerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+  EXPECT_EQ(nestedPid, status->executor_pid());
+
+  Future<Option<ContainerTermination>> nestedWait = containerizer->wait(
+      nestedContainerId);
+
+  containerizer->destroy(nestedContainerId);
+
+  AWAIT_READY(nestedWait);
+  ASSERT_SOME(nestedWait.get());
+
+  // We expect a wait status of SIGKILL on the nested container.
+  // Since the kernel will destroy these via a SIGKILL, we expect
+  // a SIGKILL here.
+  ASSERT_TRUE(nestedWait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, nestedWait.get()->status());
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+
+  containerizer->destroy(containerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+}
+
+
+TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_RecoverLauncherOrphans)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  // Now create a freezer cgroup that represents the container so
+  // when the LinuxLauncher recovers we'll treat it as an orphan.
+  //
+  // NOTE: `cgroups::hierarchy` must be called AFTER
+  // `MesosContainerizer::create` which calls `LinuxLauncher::create`
+  // which calls `cgroups::prepare`, otherwise we might not have a
+  // 'freezer' hierarchy prepared yet!
+  Result<string> freezerHierarchy = cgroups::hierarchy("freezer");
+  ASSERT_SOME(freezerHierarchy);
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  const string cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(containerId, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  ASSERT_FALSE(containers->contains(containerId));
+}
+
+
+TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_RecoverNestedLauncherOrphans)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  ExecutorInfo executor = createExecutorInfo(
+      "executor",
+      "sleep 1000",
+      "cpus:1");
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      executor,
+      directory.get(),
+      None(),
+      SlaveID(),
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<ContainerStatus> status = containerizer->status(containerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+
+  pid_t pid = status->executor_pid();
+
+  // Now create a freezer cgroup that represents the nested container
+  // so when the LinuxLauncher recovers we'll treat it as an orphan.
+  //
+  // NOTE: `cgroups::hierarchy` must be called AFTER
+  // `MesosContainerizer::create` which calls `LinuxLauncher::create`
+  // which calls `cgroups::prepare`, otherwise we might not have a
+  // 'freezer' hierarchy prepared yet!
+  Result<string> freezerHierarchy = cgroups::hierarchy("freezer");
+  ASSERT_SOME(freezerHierarchy);
+
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  const string cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(nestedContainerId, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  // Force a delete on the containerizer before we create the new one.
+  containerizer.reset();
+
+  create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  containerizer.reset(create.get());
+
+  Try<SlaveState> slaveState = createSlaveState(
+      containerId,
+      pid,
+      executor,
+      state.id,
+      flags.work_dir);
+
+  ASSERT_SOME(slaveState);
+
+  state = slaveState.get();
+  AWAIT_READY(containerizer->recover(state));
+
+  status = containerizer->status(containerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+  EXPECT_EQ(pid, status->executor_pid());
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(
+      nestedContainerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  ASSERT_FALSE(containers->contains(nestedContainerId));
+
+  wait = containerizer->wait(containerId);
+
+  containerizer->destroy(containerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+}
+
+
+TEST_F(NestedMesosContainerizerTest,
+       ROOT_CGROUPS_RecoverLauncherOrphanAndSingleNestedLauncherOrphan)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  // Now create a freezer cgroup that represents the container so
+  // when the LinuxLauncher recovers we'll treat it as an orphan.
+  //
+  // NOTE: `cgroups::hierarchy` must be called AFTER
+  // `MesosContainerizer::create` which calls `LinuxLauncher::create`
+  // which calls `cgroups::prepare`, otherwise we might not have a
+  // 'freezer' hierarchy prepared yet!
+  Result<string> freezerHierarchy = cgroups::hierarchy("freezer");
+  ASSERT_SOME(freezerHierarchy);
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  string cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(containerId, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(nestedContainerId, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(
+      nestedContainerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  ASSERT_FALSE(containers->contains(nestedContainerId));
+
+  wait = containerizer->wait(containerId);
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+
+  containers = containerizer->containers();
+  AWAIT_READY(containers);
+  ASSERT_FALSE(containers->contains(containerId));
+}
+
+
+TEST_F(NestedMesosContainerizerTest,
+       ROOT_CGROUPS_RecoverMultipleNestedLauncherOrphans)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  ExecutorInfo executor = createExecutorInfo(
+      "executor",
+      "sleep 1000",
+      "cpus:1");
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      executor,
+      directory.get(),
+      None(),
+      SlaveID(),
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<ContainerStatus> status = containerizer->status(containerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+
+  pid_t pid = status->executor_pid();
+
+  // Now create a freezer cgroup that represents the nested container
+  // so when the LinuxLauncher recovers we'll treat it as an orphan.
+  //
+  // NOTE: `cgroups::hierarchy` must be called AFTER
+  // `MesosContainerizer::create` which calls `LinuxLauncher::create`
+  // which calls `cgroups::prepare`, otherwise we might not have a
+  // 'freezer' hierarchy prepared yet!
+  Result<string> freezerHierarchy = cgroups::hierarchy("freezer");
+  ASSERT_SOME(freezerHierarchy);
+
+  ContainerID nestedContainerId1;
+  nestedContainerId1.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId1.set_value(UUID::random().toString());
+
+  string cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(nestedContainerId1, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  ContainerID nestedContainerId2;
+  nestedContainerId2.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId2.set_value(UUID::random().toString());
+
+  cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(nestedContainerId2, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  // Force a delete on the containerizer before we create the new one.
+  containerizer.reset();
+
+  create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  containerizer.reset(create.get());
+
+  Try<SlaveState> slaveState = createSlaveState(
+      containerId,
+      pid,
+      executor,
+      state.id,
+      flags.work_dir);
+
+  ASSERT_SOME(slaveState);
+
+  state = slaveState.get();
+  AWAIT_READY(containerizer->recover(state));
+
+  status = containerizer->status(containerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+  EXPECT_EQ(pid, status->executor_pid());
+
+  Future<Option<ContainerTermination>> nestedWait1 = containerizer->wait(
+      nestedContainerId1);
+
+  Future<Option<ContainerTermination>> nestedWait2 = containerizer->wait(
+      nestedContainerId2);
+
+  AWAIT_READY(nestedWait1);
+  ASSERT_SOME(nestedWait1.get());
+
+  AWAIT_READY(nestedWait2);
+  ASSERT_SOME(nestedWait2.get());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  ASSERT_FALSE(containers->contains(nestedContainerId1));
+  ASSERT_FALSE(containers->contains(nestedContainerId2));
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+
+  containerizer->destroy(containerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+}
+
+
+TEST_F(NestedMesosContainerizerTest,
+       ROOT_CGROUPS_RecoverNestedContainersWithLauncherOrphans)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  ExecutorInfo executor = createExecutorInfo(
+      "executor",
+      "sleep 1000",
+      "cpus:1");
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      executor,
+      directory.get(),
+      None(),
+      SlaveID(),
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<ContainerStatus> status = containerizer->status(containerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+
+  pid_t pid = status->executor_pid();
+
+  // Now launch the first nested container.
+  ContainerID nestedContainerId1;
+  nestedContainerId1.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId1.set_value(UUID::random().toString());
+
+  launch = containerizer->launch(
+      nestedContainerId1,
+      createCommandInfo("sleep 1000"),
+      None(),
+      None(),
+      state.id);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  status = containerizer->status(nestedContainerId1);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+
+  pid_t nestedPid1 = status->executor_pid();
+
+  // Now create a freezer cgroup that represents the nested container
+  // so when the LinuxLauncher recovers we'll treat it as an orphan.
+  //
+  // NOTE: `cgroups::hierarchy` must be called AFTER
+  // `MesosContainerizer::create` which calls `LinuxLauncher::create`
+  // which calls `cgroups::prepare`, otherwise we might not have a
+  // 'freezer' hierarchy prepared yet!
+  Result<string> freezerHierarchy = cgroups::hierarchy("freezer");
+  ASSERT_SOME(freezerHierarchy);
+
+  ContainerID nestedContainerId2;
+  nestedContainerId2.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId2.set_value(UUID::random().toString());
+
+  const string cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(nestedContainerId2, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  // Force a delete on the containerizer before we create the new one.
+  containerizer.reset();
+
+  create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  containerizer.reset(create.get());
+
+  Try<SlaveState> slaveState = createSlaveState(
+      containerId,
+      pid,
+      executor,
+      state.id,
+      flags.work_dir);
+
+  ASSERT_SOME(slaveState);
+
+  state = slaveState.get();
+  AWAIT_READY(containerizer->recover(state));
+
+  status = containerizer->status(containerId);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+  EXPECT_EQ(pid, status->executor_pid());
+
+  status = containerizer->status(nestedContainerId1);
+  AWAIT_READY(status);
+  ASSERT_TRUE(status->has_executor_pid());
+  EXPECT_EQ(nestedPid1, status->executor_pid());
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(
+      nestedContainerId2);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  ASSERT_FALSE(containers->contains(nestedContainerId2));
+
+  wait = containerizer->wait(nestedContainerId1);
+
+  containerizer->destroy(nestedContainerId1);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+
+  // We expect a wait status of SIGKILL on the nested container.
+  // Since the kernel will destroy these via a SIGKILL, we expect
+  // a SIGKILL here.
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+
+  wait = containerizer->wait(containerId);
+
+  containerizer->destroy(containerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+}
+
+
+TEST_F(NestedMesosContainerizerTest,
+       ROOT_CGROUPS_RecoverLauncherOrphanAndMultipleNestedLauncherOrphans)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      false,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  // Now create a freezer cgroup that represents the container so
+  // when the LinuxLauncher recovers we'll treat it as an orphan.
+  //
+  // NOTE: `cgroups::hierarchy` must be called AFTER
+  // `MesosContainerizer::create` which calls `LinuxLauncher::create`
+  // which calls `cgroups::prepare`, otherwise we might not have a
+  // 'freezer' hierarchy prepared yet!
+  Result<string> freezerHierarchy = cgroups::hierarchy("freezer");
+  ASSERT_SOME(freezerHierarchy);
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  string cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(containerId, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  ContainerID nestedContainerId1;
+  nestedContainerId1.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId1.set_value(UUID::random().toString());
+
+  cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(nestedContainerId1, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  ContainerID nestedContainerId2;
+  nestedContainerId2.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId2.set_value(UUID::random().toString());
+
+  cgroup = path::join(
+      flags.cgroups_root,
+      buildPath(nestedContainerId2, "mesos", JOIN));
+
+  ASSERT_SOME(cgroups::create(freezerHierarchy.get(), cgroup, true));
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  Future<Option<ContainerTermination>> nestedWait1 = containerizer->wait(
+      nestedContainerId1);
+
+  Future<Option<ContainerTermination>> nestedWait2 = containerizer->wait(
+      nestedContainerId2);
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(containerId);
+
+  AWAIT_READY(nestedWait1);
+  ASSERT_SOME(nestedWait1.get());
+
+  AWAIT_READY(nestedWait2);
+  ASSERT_SOME(nestedWait2.get());
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  ASSERT_FALSE(containers->contains(nestedContainerId1));
+  ASSERT_FALSE(containers->contains(nestedContainerId2));
+  ASSERT_FALSE(containers->contains(containerId));
+}
+
+
+TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_WaitAfterDestroy)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      true,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveID slaveId = SlaveID();
+
+  // Launch a top-level container.
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      createExecutorInfo("executor", "sleep 1000", "cpus:1"),
+      directory.get(),
+      None(),
+      slaveId,
+      map<string, string>(),
+      true);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  // Launch a nested container.
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo("exit 42"),
+      None(),
+      None(),
+      slaveId);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  // Wait once (which does a destroy),
+  // then wait again on the nested container.
+  Future<Option<ContainerTermination>> nestedWait = containerizer->wait(
+      nestedContainerId);
+
+  AWAIT_READY(nestedWait);
+  ASSERT_SOME(nestedWait.get());
+  ASSERT_TRUE(nestedWait.get()->has_status());
+  EXPECT_WEXITSTATUS_EQ(42, nestedWait.get()->status());
+
+  nestedWait = containerizer->wait(nestedContainerId);
+
+  AWAIT_READY(nestedWait);
+  ASSERT_SOME(nestedWait.get());
+  ASSERT_TRUE(nestedWait.get()->has_status());
+  EXPECT_WEXITSTATUS_EQ(42, nestedWait.get()->status());
+
+  // Destroy the top-level container.
+  Future<Option<ContainerTermination>> wait = containerizer->wait(
+      containerId);
+
+  AWAIT_READY(containerizer->destroy(containerId));
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+
+  // Wait on nested container again.
+  nestedWait = containerizer->wait(nestedContainerId);
+
+  AWAIT_READY(nestedWait);
+  ASSERT_NONE(nestedWait.get());
+}
+
+} // namespace tests {
+} // namespace internal {
+} // namespace mesos {


[3/4] mesos git commit: Merged TestIsolator and MockIsolator and added a comment.

Posted by be...@apache.org.
Merged TestIsolator and MockIsolator and added a comment.

Review: https://reviews.apache.org/r/52474


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/8ecea161
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/8ecea161
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/8ecea161

Branch: refs/heads/master
Commit: 8ecea16118f957e358f96ccb0981b2fec18c5656
Parents: 66d4b26
Author: Benjamin Hindman <be...@gmail.com>
Authored: Sun Oct 2 20:06:10 2016 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Mon Oct 3 19:20:26 2016 -0700

----------------------------------------------------------------------
 src/tests/containerizer/isolator.hpp            | 87 +++++++++++++-------
 .../containerizer/mesos_containerizer_tests.cpp | 75 ++---------------
 2 files changed, 64 insertions(+), 98 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/8ecea161/src/tests/containerizer/isolator.hpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/isolator.hpp b/src/tests/containerizer/isolator.hpp
index fbe80aa..86664a8 100644
--- a/src/tests/containerizer/isolator.hpp
+++ b/src/tests/containerizer/isolator.hpp
@@ -25,16 +25,62 @@ namespace mesos {
 namespace internal {
 namespace tests {
 
-class TestIsolatorProcess : public slave::MesosIsolatorProcess
+// Provides a mock Isolator that by default expects calls to
+// Isolator::prepare, Isolator::isolate, Isolator::watch, and
+// Isolator::cleanup and simply returns "nothing" as appropriate for
+// each call. This behavior can be overriden by adding EXPECT_CALL as
+// necessary. For example, if you don't expect any calls to
+// Isolator::cleanup you can do:
+//
+//   MockIsolator isolator;
+//   EXPECT_CALL(isolator, prepare(_, _))
+//    .Times(0);
+//
+// Or if you want to override that only a single invocation should
+// occur you can do:
+//
+//   MockIsolator isolator;
+//   EXPECT_CALL(isolator, prepare(_, _))
+//    .WillOnce(Return(ContainerLaunchInfo(...)));
+//
+// But note that YOU MUST use exactly `prepare(_, _)` otherwise gmock
+// will not properly match this new expectation with the default
+// expectation created by MockIsolator.
+//
+// In the event you want to override a single invocation but let all
+// subsequent invocations return the "default" you can do:
+//
+//   MockIsolator isolator;
+//   EXPECT_CALL(isolator, prepare(_, _))
+//    .WillOnce(Return(ContainerLaunchInfo(...)))
+//    .RetiresOnSaturation();
+//
+// Another example, if you want to override what gets returned for a
+// every invocation you can do:
+//
+//   MockIsolator isolator;
+//   EXPECT_CALL(isolator, prepare(_, _))
+//    .WillRepeatedly(Return(Failure(...)));
+//
+// Again, YOU MUST use exactly `prepare(_, _)` to override the default
+// expectation.
+class MockIsolator : public mesos::slave::Isolator
 {
 public:
-  static Try<mesos::slave::Isolator*> create(
-      const Option<mesos::slave::ContainerLaunchInfo>& prepare)
+  MockIsolator()
   {
-    process::Owned<MesosIsolatorProcess> process(
-        new TestIsolatorProcess(prepare));
+    EXPECT_CALL(*this, prepare(_, _))
+      .WillRepeatedly(Return(None()));
+
+    EXPECT_CALL(*this, isolate(_, _))
+      .WillRepeatedly(Return(Nothing()));
+
+    EXPECT_CALL(*this, watch(_))
+      .WillRepeatedly(
+          Return(process::Future<mesos::slave::ContainerLimitation>()));
 
-    return new slave::MesosIsolator(process);
+    EXPECT_CALL(*this, cleanup(_))
+      .WillRepeatedly(Return(Nothing()));
   }
 
   MOCK_METHOD2(
@@ -43,12 +89,11 @@ public:
           const std::list<mesos::slave::ContainerState>&,
           const hashset<ContainerID>&));
 
-  virtual process::Future<Option<mesos::slave::ContainerLaunchInfo>> prepare(
-      const ContainerID& containerId,
-      const mesos::slave::ContainerConfig& containerConfig)
-  {
-    return launchInfo;
-  }
+  MOCK_METHOD2(
+      prepare,
+      process::Future<Option<mesos::slave::ContainerLaunchInfo>>(
+          const ContainerID&,
+          const mesos::slave::ContainerConfig&));
 
   MOCK_METHOD2(
       isolate,
@@ -69,24 +114,6 @@ public:
   MOCK_METHOD1(
       cleanup,
       process::Future<Nothing>(const ContainerID&));
-
-private:
-  TestIsolatorProcess( const Option<mesos::slave::ContainerLaunchInfo>& info)
-    : launchInfo(info)
-  {
-    EXPECT_CALL(*this, watch(testing::_))
-      .WillRepeatedly(testing::Return(promise.future()));
-
-    EXPECT_CALL(*this, isolate(testing::_, testing::_))
-      .WillRepeatedly(testing::Return(Nothing()));
-
-    EXPECT_CALL(*this, cleanup(testing::_))
-      .WillRepeatedly(testing::Return(Nothing()));
-  }
-
-  const Option<mesos::slave::ContainerLaunchInfo> launchInfo;
-
-  process::Promise<mesos::slave::ContainerLimitation> promise;
 };
 
 } // namespace tests {

http://git-wip-us.apache.org/repos/asf/mesos/blob/8ecea161/src/tests/containerizer/mesos_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/mesos_containerizer_tests.cpp b/src/tests/containerizer/mesos_containerizer_tests.cpp
index f64ec5d..7872c74 100644
--- a/src/tests/containerizer/mesos_containerizer_tests.cpp
+++ b/src/tests/containerizer/mesos_containerizer_tests.cpp
@@ -201,8 +201,8 @@ TEST_F(MesosContainerizerTest, Destroy)
 class MesosContainerizerIsolatorPreparationTest : public MesosTest
 {
 public:
-  // Construct a MesosContainerizer with TestIsolator(s) which use the provided
-  // 'prepare' command(s).
+  // Construct a MesosContainerizer with MockIsolator(s) which return
+  // the provided ContainerLaunchInfo for Isolator::prepare.
   Try<Owned<MesosContainerizer>> CreateContainerizer(
       Fetcher* fetcher,
       const vector<Option<ContainerLaunchInfo>>& launchInfos)
@@ -210,12 +210,12 @@ public:
     vector<Owned<Isolator>> isolators;
 
     foreach (const Option<ContainerLaunchInfo>& launchInfo, launchInfos) {
-      Try<Isolator*> isolator = TestIsolatorProcess::create(launchInfo);
-      if (isolator.isError()) {
-        return Error(isolator.error());
-      }
+      MockIsolator* isolator = new MockIsolator();
 
-      isolators.push_back(Owned<Isolator>(isolator.get()));
+      EXPECT_CALL(*isolator, prepare(_, _))
+        .WillOnce(Return(launchInfo));
+
+      isolators.push_back(Owned<Isolator>(isolator));
     }
 
     slave::Flags flags = CreateSlaveFlags();
@@ -628,67 +628,6 @@ public:
 };
 
 
-class MockIsolator : public mesos::slave::Isolator
-{
-public:
-  MockIsolator()
-  {
-    EXPECT_CALL(*this, watch(_))
-      .WillRepeatedly(Return(watchPromise.future()));
-
-    EXPECT_CALL(*this, isolate(_, _))
-      .WillRepeatedly(Return(Nothing()));
-
-    EXPECT_CALL(*this, cleanup(_))
-      .WillRepeatedly(Return(Nothing()));
-
-    EXPECT_CALL(*this, prepare(_, _))
-      .WillRepeatedly(Invoke(this, &MockIsolator::_prepare));
-  }
-
-  MOCK_METHOD2(
-      recover,
-      Future<Nothing>(
-          const list<ContainerState>&,
-          const hashset<ContainerID>&));
-
-  MOCK_METHOD2(
-      prepare,
-      Future<Option<ContainerLaunchInfo>>(
-          const ContainerID&,
-          const ContainerConfig&));
-
-  virtual Future<Option<ContainerLaunchInfo>> _prepare(
-      const ContainerID& containerId,
-      const ContainerConfig& containerConfig)
-  {
-    return None();
-  }
-
-  MOCK_METHOD2(
-      isolate,
-      Future<Nothing>(const ContainerID&, pid_t));
-
-  MOCK_METHOD1(
-      watch,
-      Future<mesos::slave::ContainerLimitation>(const ContainerID&));
-
-  MOCK_METHOD2(
-      update,
-      Future<Nothing>(const ContainerID&, const Resources&));
-
-  MOCK_METHOD1(
-      usage,
-      Future<ResourceStatistics>(const ContainerID&));
-
-  MOCK_METHOD1(
-      cleanup,
-      Future<Nothing>(const ContainerID&));
-
-  Promise<mesos::slave::ContainerLimitation> watchPromise;
-};
-
-
 // Destroying a mesos containerizer while it is fetching should
 // complete without waiting for the fetching to finish.
 TEST_F(MesosContainerizerDestroyTest, DestroyWhileFetching)