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 2013/04/04 22:57:59 UTC

svn commit: r1464756 - in /incubator/mesos/trunk/src: Makefile.am tests/cluster.hpp tests/isolator.hpp tests/master_tests.cpp tests/state_tests.cpp tests/utils.hpp

Author: benh
Date: Thu Apr  4 20:57:58 2013
New Revision: 1464756

URL: http://svn.apache.org/r1464756
Log:
Added and used new Cluster abstraction for testing.

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

Added:
    incubator/mesos/trunk/src/tests/cluster.hpp
    incubator/mesos/trunk/src/tests/isolator.hpp
Modified:
    incubator/mesos/trunk/src/Makefile.am
    incubator/mesos/trunk/src/tests/master_tests.cpp
    incubator/mesos/trunk/src/tests/state_tests.cpp
    incubator/mesos/trunk/src/tests/utils.hpp

Modified: incubator/mesos/trunk/src/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/Makefile.am?rev=1464756&r1=1464755&r2=1464756&view=diff
==============================================================================
--- incubator/mesos/trunk/src/Makefile.am (original)
+++ incubator/mesos/trunk/src/Makefile.am Thu Apr  4 20:57:58 2013
@@ -234,6 +234,8 @@ libmesos_no_third_party_la_SOURCES += co
 	slave/slave.hpp							\
 	tests/environment.hpp tests/script.hpp				\
 	tests/zookeeper_test.hpp tests/flags.hpp tests/utils.hpp	\
+	tests/cluster.hpp						\
+	tests/isolator.hpp						\
 	tests/zookeeper_test_server.hpp zookeeper/authentication.hpp	\
 	zookeeper/group.hpp zookeeper/watcher.hpp			\
 	zookeeper/zookeeper.hpp zookeeper/url.hpp

Added: incubator/mesos/trunk/src/tests/cluster.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/cluster.hpp?rev=1464756&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/cluster.hpp (added)
+++ incubator/mesos/trunk/src/tests/cluster.hpp Thu Apr  4 20:57:58 2013
@@ -0,0 +1,476 @@
+/**
+ * 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.
+ */
+
+#ifndef __TESTS_CLUSTER_HPP__
+#define __TESTS_CLUSTER_HPP__
+
+#include <map>
+
+#include <process/pid.hpp>
+#include <process/process.hpp>
+
+#include <stout/error.hpp>
+#include <stout/foreach.hpp>
+#include <stout/none.hpp>
+#include <stout/nothing.hpp>
+#include <stout/option.hpp>
+#include <stout/owned.hpp>
+#include <stout/try.hpp>
+
+#include "detector/detector.hpp"
+
+#include "files/files.hpp"
+
+#include "master/allocator.hpp"
+#include "master/hierarchical_allocator_process.hpp"
+#include "master/flags.hpp"
+#include "master/master.hpp"
+
+#include "slave/flags.hpp"
+#include "slave/isolator.hpp"
+#include "slave/slave.hpp"
+
+#include "tests/isolator.hpp" // For TestingIsolator.
+
+#include "zookeeper/url.hpp"
+
+namespace mesos {
+namespace internal {
+namespace tests {
+
+class Cluster
+{
+public:
+  // TODO(benh): Take flags and make const in Masters and Slaves.
+  Cluster(const Option<zookeeper::URL>& url = None())
+    : masters(this, url),
+      slaves(this, &masters) {}
+
+  // Abstracts the masters of a cluster.
+  class Masters
+  {
+  public:
+    Masters(Cluster* _cluster, const Option<zookeeper::URL>& _url);
+    ~Masters();
+
+    void shutdown();
+
+    // Start and manage a new master.
+    Try<process::PID<master::Master> > start();
+    Try<process::PID<master::Master> > start(const master::Flags& flags);
+
+    // Stops and cleans up a master at the specified PID.
+    Try<Nothing> stop(const process::PID<master::Master>& pid);
+
+    // Returns a new master detector for this instance of masters.
+    Owned<MasterDetector> detector(
+        const process::PID<slave::Slave>& pid,
+        bool quiet);
+
+    // "Default" flags used for creating masters.
+    master::Flags flags;
+
+  private:
+    // Not copyable, not assignable.
+    Masters(const Masters&);
+    Masters& operator = (const Masters&);
+
+    Cluster* cluster; // Enclosing class.
+    Option<zookeeper::URL> url;
+
+    struct Master
+    {
+      Master()
+        : master(NULL),
+          allocator(NULL),
+          allocatorProcess(NULL),
+          detector(NULL) {}
+
+      master::Master* master;
+      master::Allocator* allocator;
+      master::AllocatorProcess* allocatorProcess;
+      MasterDetector* detector;
+    };
+
+    std::map<process::PID<master::Master>, Master> masters;
+  };
+
+  // Abstracts the slaves of a cluster.
+  class Slaves
+  {
+  public:
+    Slaves(Cluster* _cluster, Masters* _masters);
+    ~Slaves();
+
+    // Stop and clean up all slaves.
+    void shutdown();
+
+    // Start and manage a new slave.
+    Try<process::PID<slave::Slave> > start();
+    Try<process::PID<slave::Slave> > start(const slave::Flags& flags);
+    Try<process::PID<slave::Slave> > start(
+        const ExecutorID& executorId,
+        Executor* executor);
+    Try<process::PID<slave::Slave> > start(slave::Isolator* isolator);
+    Try<process::PID<slave::Slave> > start(
+        const slave::Flags& flags,
+        slave::Isolator* isolator);
+
+    // Stops and cleans up a slave at the specified PID.
+    Try<Nothing> stop(const process::PID<slave::Slave>& pid);
+
+    // "Default" flags used for creating slaves.
+    slave::Flags flags;
+
+  private:
+    // Not copyable, not assignable.
+    Slaves(const Slaves&);
+    Slaves& operator = (const Slaves&);
+
+    Cluster* cluster; // Enclosing class.
+    Masters* masters; // Used to create MasterDetector instances.
+
+    struct Slave
+    {
+      Slave()
+        : slave(NULL),
+          isolator(NULL),
+          detector(NULL) {}
+
+      slave::Slave* slave;
+      slave::Isolator* isolator;
+      Owned<MasterDetector> detector;
+    };
+
+    std::map<process::PID<slave::Slave>, Slave> slaves;
+  };
+
+  // Shuts down all masters and slaves.
+  void shutdown()
+  {
+    masters.shutdown();
+    slaves.shutdown();
+  }
+
+  // Cluster wide shared abstractions.
+  Files files;
+
+  Masters masters;
+  Slaves slaves;
+
+private:
+  // Not copyable, not assignable.
+  Cluster(const Cluster&);
+  Cluster& operator = (const Cluster&);
+};
+
+
+inline Cluster::Masters::Masters(
+    Cluster* _cluster,
+    const Option<zookeeper::URL>& _url)
+  : cluster(_cluster),
+    url(_url) {}
+
+
+inline Cluster::Masters::~Masters()
+{
+  shutdown();
+}
+
+
+inline void Cluster::Masters::shutdown()
+{
+  // TODO(benh): Use utils::copy from stout once namespaced.
+  std::map<process::PID<master::Master>, Master> copy(masters);
+  foreachkey (const process::PID<master::Master>& pid, copy) {
+    stop(pid);
+  }
+  masters.clear();
+}
+
+
+inline Try<process::PID<master::Master> > Cluster::Masters::start()
+{
+  // Disallow multiple masters when not using ZooKeeper.
+  if (!masters.empty() && url.isNone()) {
+    return Error("Can not start multiple masters when not using ZooKeeper");
+  }
+
+  Master master;
+  master.allocatorProcess = new master::HierarchicalDRFAllocatorProcess();
+  master.allocator = new master::Allocator(master.allocatorProcess);
+  master.master = new master::Master(master.allocator, &cluster->files, flags);
+
+  process::PID<master::Master> pid = process::spawn(master.master);
+
+  if (url.isSome()) {
+    master.detector = new ZooKeeperMasterDetector(url.get(), pid, true, true);
+  } else {
+    master.detector = new BasicMasterDetector(pid);
+  }
+
+  masters[pid] = master;
+
+  return pid;
+}
+
+
+inline Try<process::PID<master::Master> > Cluster::Masters::start(
+    const master::Flags& flags)
+{
+  // Disallow multiple masters when not using ZooKeeper.
+  if (!masters.empty() && url.isNone()) {
+    return Error("Can not start multiple masters when not using ZooKeeper");
+  }
+
+  Master master;
+  master.allocatorProcess = new master::HierarchicalDRFAllocatorProcess();
+  master.allocator = new master::Allocator(master.allocatorProcess);
+  master.master = new master::Master(master.allocator, &cluster->files, flags);
+
+  process::PID<master::Master> pid = process::spawn(master.master);
+
+  if (url.isSome()) {
+    master.detector = new ZooKeeperMasterDetector(url.get(), pid, true, true);
+  } else {
+    master.detector = new BasicMasterDetector(pid);
+  }
+
+  masters[pid] = master;
+
+  return pid;
+}
+
+
+inline Try<Nothing> Cluster::Masters::stop(
+    const process::PID<master::Master>& pid)
+{
+  if (masters.count(pid) == 0) {
+    return Error("No master found to stop");
+  }
+
+  Master master = masters[pid];
+
+  process::terminate(master.master);
+  process::wait(master.master);
+  delete master.master;
+
+  delete master.allocator; // Terminates and waits for the allocator process.
+  delete master.allocatorProcess;
+
+  delete master.detector;
+
+  masters.erase(pid);
+
+  return Nothing();
+}
+
+
+inline Owned<MasterDetector> Cluster::Masters::detector(
+    const process::PID<slave::Slave>& pid,
+    bool quiet)
+{
+  if (url.isSome()) {
+    return new ZooKeeperMasterDetector(url.get(), pid, false, quiet);
+  }
+
+  CHECK(masters.size() == 1);
+  return new BasicMasterDetector(masters.begin()->first, pid);
+}
+
+
+inline Cluster::Slaves::Slaves(Cluster* _cluster, Masters* _masters)
+  : cluster(_cluster), masters(_masters) {}
+
+
+inline Cluster::Slaves::~Slaves()
+{
+  shutdown();
+}
+
+
+inline void Cluster::Slaves::shutdown()
+{
+  // TODO(benh): Use utils::copy from stout once namespaced.
+  std::map<process::PID<slave::Slave>, Slave> copy(slaves);
+  foreachkey (const process::PID<slave::Slave>& pid, copy) {
+    stop(pid);
+  }
+  slaves.clear();
+}
+
+
+inline Try<process::PID<slave::Slave> > Cluster::Slaves::start()
+{
+  // TODO(benh): Check that we dont have another slave already running
+  // with flags that conflict (e.g., work_dir).
+
+  Slave slave;
+
+  slave.isolator = new TestingIsolator();
+
+  process::spawn(slave.isolator);
+
+  // TODO(benh): Create a work directory for each slave.
+
+  slave.slave = new slave::Slave(flags, true, slave.isolator, &cluster->files);
+
+  process::PID<slave::Slave> pid = process::spawn(slave.slave);
+
+  // Get a detector for the master(s).
+  slave.detector = masters->detector(pid, flags.quiet);
+
+  slaves[pid] = slave;
+
+  return pid;
+}
+
+
+inline Try<process::PID<slave::Slave> > Cluster::Slaves::start(
+    const slave::Flags& flags)
+{
+  // TODO(benh): Check that we dont have another slave already running
+  // with flags that conflict (e.g., work_dir).
+
+  Slave slave;
+
+  slave.isolator = new TestingIsolator();
+
+  process::spawn(slave.isolator);
+
+  // TODO(benh): Create a work directory for each slave.
+
+  slave.slave = new slave::Slave(flags, true, slave.isolator, &cluster->files);
+
+  process::PID<slave::Slave> pid = process::spawn(slave.slave);
+
+  // Get a detector for the master(s).
+  slave.detector = masters->detector(pid, flags.quiet);
+
+  slaves[pid] = slave;
+
+  return pid;
+}
+
+
+inline Try<process::PID<slave::Slave> > Cluster::Slaves::start(
+    const ExecutorID& executorId,
+    Executor* executor)
+{
+  // TODO(benh): Check that we dont have another slave already running
+  // with flags that conflict (e.g., work_dir).
+
+  Slave slave;
+
+  slave.isolator = new TestingIsolator(executorId, executor);
+
+  process::spawn(slave.isolator);
+
+  // TODO(benh): Create a work directory for each slave.
+
+  slave.slave = new slave::Slave(flags, true, slave.isolator, &cluster->files);
+
+  process::PID<slave::Slave> pid = process::spawn(slave.slave);
+
+  // Get a detector for the master(s).
+  slave.detector = masters->detector(pid, flags.quiet);
+
+  slaves[pid] = slave;
+
+  return pid;
+}
+
+
+inline Try<process::PID<slave::Slave> > Cluster::Slaves::start(
+    slave::Isolator* isolator)
+{
+  // TODO(benh): Check that we dont have another slave already running
+  // with flags that conflict (e.g., work_dir).
+
+  Slave slave;
+
+  // TODO(benh): Create a work directory for each slave.
+
+  slave.slave = new slave::Slave(flags, true, isolator, &cluster->files);
+
+  process::PID<slave::Slave> pid = process::spawn(slave.slave);
+
+  // Get a detector for the master(s).
+  slave.detector = masters->detector(pid, flags.quiet);
+
+  slaves[pid] = slave;
+
+  return pid;
+}
+
+
+inline Try<process::PID<slave::Slave> > Cluster::Slaves::start(
+    const slave::Flags& flags,
+    slave::Isolator* isolator)
+{
+  // TODO(benh): Check that we dont have another slave already running
+  // with flags that conflict (e.g., work_dir).
+
+  Slave slave;
+
+  // TODO(benh): Create a work directory for each slave.
+
+  slave.slave = new slave::Slave(flags, true, isolator, &cluster->files);
+
+  process::PID<slave::Slave> pid = process::spawn(slave.slave);
+
+  // Get a detector for the master(s).
+  slave.detector = masters->detector(pid, flags.quiet);
+
+  slaves[pid] = slave;
+
+  return pid;
+}
+
+
+inline Try<Nothing> Cluster::Slaves::stop(
+    const process::PID<slave::Slave>& pid)
+{
+  if (slaves.count(pid) == 0) {
+    return Error("No slave found to stop");
+  }
+
+  Slave slave = slaves[pid];
+
+  process::terminate(slave.slave);
+  process::wait(slave.slave);
+  delete slave.slave;
+
+  if (slave.isolator != NULL) {
+    // TODO(benh): Terminate and wait for the isolator once the slave
+    // is no longer doing so.
+    // process::terminate(slave.isolator);
+    // process::wait(slave.isolator);
+    delete slave.isolator;
+  }
+
+  slaves.erase(pid);
+
+  return Nothing();
+}
+
+} // namespace tests {
+} // namespace internal {
+} // namespace mesos {
+
+#endif // __TESTS_CLUSTER_HPP__

Added: incubator/mesos/trunk/src/tests/isolator.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/isolator.hpp?rev=1464756&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/isolator.hpp (added)
+++ incubator/mesos/trunk/src/tests/isolator.hpp Thu Apr  4 20:57:58 2013
@@ -0,0 +1,180 @@
+/**
+ * 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.
+ */
+
+#ifndef __TESTS_ISOLATOR_HPP__
+#define __TESTS_ISOLATOR_HPP__
+
+#include <map>
+#include <string>
+
+#include <process/dispatch.hpp>
+#include <process/future.hpp>
+#include <process/pid.hpp>
+
+#include <stout/try.hpp>
+#include <stout/uuid.hpp>
+
+#include "slave/isolator.hpp"
+
+namespace mesos {
+namespace internal {
+namespace tests {
+
+class TestingIsolator : public slave::Isolator
+{
+public:
+  TestingIsolator()
+  {
+    setup();
+  }
+
+  TestingIsolator(const std::map<ExecutorID, Executor*>& _executors)
+    : executors(_executors)
+  {
+    setup();
+  }
+
+  TestingIsolator(const ExecutorID& executorId, Executor* executor)
+  {
+    executors[executorId] = executor;
+    setup();
+  }
+
+  virtual ~TestingIsolator() {}
+
+  virtual void initialize(
+      const slave::Flags& flags,
+      const Resources& resources,
+      bool local,
+      const process::PID<slave::Slave>& _slave)
+  {
+    slave = _slave;
+  }
+
+  virtual void launchExecutor(
+      const SlaveID& slaveId,
+      const FrameworkID& frameworkId,
+      const FrameworkInfo& frameworkInfo,
+      const ExecutorInfo& executorInfo,
+      const UUID& uuid,
+      const std::string& directory,
+      const Resources& resources,
+      const Option<std::string>& path)
+  {
+    if (executors.count(executorInfo.executor_id()) > 0) {
+      Executor* executor = executors[executorInfo.executor_id()];
+      MesosExecutorDriver* driver = new MesosExecutorDriver(executor);
+      drivers[executorInfo.executor_id()] = driver;
+
+      directories[executorInfo.executor_id()] = directory;
+
+      os::setenv("MESOS_LOCAL", "1");
+      os::setenv("MESOS_DIRECTORY", directory);
+      os::setenv("MESOS_SLAVE_PID", slave);
+      os::setenv("MESOS_SLAVE_ID", slaveId.value());
+      os::setenv("MESOS_FRAMEWORK_ID", frameworkId.value());
+      os::setenv("MESOS_EXECUTOR_ID", executorInfo.executor_id().value());
+      os::setenv("MESOS_CHECKPOINT", frameworkInfo.checkpoint() ? "1" : "0");
+
+      driver->start();
+
+      os::unsetenv("MESOS_LOCAL");
+      os::unsetenv("MESOS_DIRECTORY");
+      os::unsetenv("MESOS_SLAVE_PID");
+      os::unsetenv("MESOS_SLAVE_ID");
+      os::unsetenv("MESOS_FRAMEWORK_ID");
+      os::unsetenv("MESOS_EXECUTOR_ID");
+      os::unsetenv("MESOS_CHECKPOINT");
+
+      process::dispatch(
+          slave,
+          &slave::Slave::executorStarted,
+          frameworkId,
+          executorInfo.executor_id(),
+          -1);
+
+    } else {
+      FAIL() << "Cannot launch executor";
+    }
+  }
+
+  virtual void killExecutor(
+      const FrameworkID& frameworkId,
+      const ExecutorID& executorId)
+  {
+    if (drivers.count(executorId) > 0) {
+      MesosExecutorDriver* driver = drivers[executorId];
+      driver->stop();
+      driver->join();
+      delete driver;
+      drivers.erase(executorId);
+
+      process::dispatch(
+          slave,
+          &slave::Slave::executorTerminated,
+          frameworkId,
+          executorId,
+          0,
+          false,
+          "Killed executor");
+    } else {
+      FAIL() << "Cannot kill executor";
+    }
+  }
+
+  // Mocked so tests can check that the resources reflect all started tasks.
+  MOCK_METHOD3(resourcesChanged, void(const FrameworkID&,
+                                      const ExecutorID&,
+                                      const Resources&));
+
+  MOCK_METHOD2(
+      usage,
+      process::Future<ResourceStatistics>(
+          const FrameworkID&,
+          const ExecutorID&));
+
+  MOCK_METHOD1(
+      recover,
+      process::Future<Nothing>(const Option<slave::state::SlaveState>&));
+
+  std::map<ExecutorID, std::string> directories;
+
+private:
+  // Helper to setup default expectations.
+  void setup()
+  {
+    EXPECT_CALL(*this, resourcesChanged(testing::_, testing::_, testing::_))
+      .Times(testing::AnyNumber());
+
+    EXPECT_CALL(*this, usage(testing::_, testing::_))
+      .WillRepeatedly(testing::Return(ResourceStatistics()));
+
+    EXPECT_CALL(*this, recover(testing::_))
+      .WillRepeatedly(testing::Return(Nothing()));
+  }
+
+  std::map<ExecutorID, Executor*> executors;
+  std::map<ExecutorID, MesosExecutorDriver*> drivers;
+  process::PID<slave::Slave> slave;
+};
+
+} // namespace tests {
+} // namespace internal {
+} // namespace mesos {
+
+#endif // __TESTS_ISOLATOR_HPP__

Modified: incubator/mesos/trunk/src/tests/master_tests.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/master_tests.cpp?rev=1464756&r1=1464755&r2=1464756&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/master_tests.cpp (original)
+++ incubator/mesos/trunk/src/tests/master_tests.cpp Thu Apr  4 20:57:58 2013
@@ -38,23 +38,20 @@
 
 #include "flags/flags.hpp"
 
-#include "master/allocator.hpp"
 #include "master/flags.hpp"
-#include "master/hierarchical_allocator_process.hpp"
 #include "master/master.hpp"
 
 #include "slave/constants.hpp"
 #include "slave/process_isolator.hpp"
 #include "slave/slave.hpp"
 
+#include "tests/cluster.hpp"
 #include "tests/utils.hpp"
 
 using namespace mesos;
 using namespace mesos::internal;
 using namespace mesos::internal::tests;
 
-using mesos::internal::master::Allocator;
-using mesos::internal::master::HierarchicalDRFAllocatorProcess;
 using mesos::internal::master::Master;
 
 using mesos::internal::slave::Isolator;
@@ -76,30 +73,25 @@ using testing::Eq;
 using testing::Return;
 
 
-class MasterTest : public MesosTest {};
+class MasterTest : public MesosClusterTest {};
 
 
 TEST_F(MasterTest, TaskRunning)
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
   MockExecutor exec;
 
   TestingIsolator isolator(DEFAULT_EXECUTOR_ID, &exec);
 
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  Try<PID<Slave> > slave = cluster.slaves.start(&isolator);
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -155,11 +147,7 @@ TEST_F(MasterTest, TaskRunning)
 
   AWAIT_UNTIL(shutdown); // Ensures MockExecutor can be deallocated.
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown(); // Must shutdown before 'isolator' gets deallocated.
 }
 
 
@@ -167,24 +155,20 @@ TEST_F(MasterTest, ShutdownFrameworkWhil
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
   MockExecutor exec;
 
   TestingIsolator isolator(DEFAULT_EXECUTOR_ID, &exec);
 
-  slaveFlags.executor_shutdown_grace_period = Seconds(0.0);
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  slave::Flags flags = cluster.slaves.flags;
+  flags.executor_shutdown_grace_period = Seconds(0);
+  Try<PID<Slave> > slave = cluster.slaves.start(flags, &isolator);
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -240,11 +224,7 @@ TEST_F(MasterTest, ShutdownFrameworkWhil
 
   AWAIT_UNTIL(shutdown); // Ensures MockExecutor can be deallocated.
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown(); // Must shutdown before 'isolator' gets deallocated.
 }
 
 
@@ -252,23 +232,16 @@ TEST_F(MasterTest, KillTask)
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
   MockExecutor exec;
 
-  TestingIsolator isolator(DEFAULT_EXECUTOR_ID, &exec);
-
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  Try<PID<Slave> > slave = cluster.slaves.start(DEFAULT_EXECUTOR_ID, &exec);
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -331,11 +304,7 @@ TEST_F(MasterTest, KillTask)
 
   AWAIT_UNTIL(shutdown); // To ensure can deallocate MockExecutor.
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown();
 }
 
 
@@ -343,23 +312,16 @@ TEST_F(MasterTest, StatusUpdateAck)
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
   MockExecutor exec;
 
-  TestingIsolator isolator(DEFAULT_EXECUTOR_ID, &exec);
-
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  Try<PID<Slave> > slave = cluster.slaves.start(DEFAULT_EXECUTOR_ID, &exec);
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -393,7 +355,7 @@ TEST_F(MasterTest, StatusUpdateAck)
   Future<Nothing> acknowledgement;
   EXPECT_MESSAGE(Eq(StatusUpdateAcknowledgementMessage().GetTypeName()),
                  _,
-                 Eq(slave))
+                 Eq(slave.get()))
     .WillOnce(DoAll(FutureSatisfy(&acknowledgement),
                     Return(false)));
 
@@ -418,11 +380,7 @@ TEST_F(MasterTest, StatusUpdateAck)
 
   AWAIT_UNTIL(shutdown); // Ensures MockExecutor can be deallocated.
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown();
 }
 
 
@@ -430,25 +388,21 @@ TEST_F(MasterTest, RecoverResources)
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
   MockExecutor exec;
 
   TestingIsolator isolator(DEFAULT_EXECUTOR_ID, &exec);
 
-  setSlaveResources("cpus:2;mem:1024;disk:1024;ports:[1-10, 20-30]");
-
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  slave::Flags flags = cluster.slaves.flags;
+  flags.resources =
+    Option<string>("cpus:2;mem:1024;disk:1024;ports:[1-10, 20-30]");
+  Try<PID<Slave> > slave = cluster.slaves.start(flags, &isolator);
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -538,8 +492,7 @@ TEST_F(MasterTest, RecoverResources)
 
   AWAIT_UNTIL(offers);
   EXPECT_NE(0u, offers.get().size());
-
-  Resources slaveResources = Resources::parse(slaveFlags.resources.get());
+  Resources slaveResources = Resources::parse(flags.resources.get());
   EXPECT_EQ(slaveResources, offers.get()[0].resources());
 
   driver.stop();
@@ -550,11 +503,7 @@ TEST_F(MasterTest, RecoverResources)
   EXPECT_CALL(exec, shutdown(_))
     .Times(AtMost(1));
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown(); // Must shutdown before 'isolator' gets deallocated.
 }
 
 
@@ -562,26 +511,16 @@ TEST_F(MasterTest, FrameworkMessage)
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
   MockExecutor exec;
 
-  TestingIsolator isolator(DEFAULT_EXECUTOR_ID, &exec);
-
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
-
-  // Launch the first (i.e., failing) scheduler and wait until the
-  // first status update message is sent to it (drop the message).
+  Try<PID<Slave> > slave = cluster.slaves.start(DEFAULT_EXECUTOR_ID, &exec);
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver schedDriver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver schedDriver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&schedDriver, _, _))
     .Times(1);
@@ -650,11 +589,7 @@ TEST_F(MasterTest, FrameworkMessage)
 
   AWAIT_UNTIL(shutdown); // To ensure can deallocate MockExecutor.
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown();
 }
 
 
@@ -662,11 +597,8 @@ TEST_F(MasterTest, MultipleExecutors)
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
   ExecutorID executorId1;
   executorId1.set_value("executor-1");
@@ -683,13 +615,11 @@ TEST_F(MasterTest, MultipleExecutors)
 
   TestingIsolator isolator(execs);
 
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  Try<PID<Slave> > slave = cluster.slaves.start(&isolator);
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -777,11 +707,7 @@ TEST_F(MasterTest, MultipleExecutors)
   AWAIT_UNTIL(shutdown1); // To ensure can deallocate MockExecutor.
   AWAIT_UNTIL(shutdown2); // To ensure can deallocate MockExecutor.
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown(); // Must shutdown before 'isolator' gets deallocated.
 }
 
 
@@ -789,21 +715,16 @@ TEST_F(MasterTest, ShutdownUnregisteredE
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
   ProcessIsolator isolator;
 
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  Try<PID<Slave> > slave = cluster.slaves.start(&isolator);
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -856,7 +777,7 @@ TEST_F(MasterTest, ShutdownUnregisteredE
                     Return(false)))
     .WillRepeatedly(Return(false)); // TODO(benh): Why is this needed?
 
-  Clock::advance(slaveFlags.executor_registration_timeout.secs());
+  Clock::advance(cluster.slaves.flags.executor_registration_timeout.secs());
 
   AWAIT_UNTIL(killExecutor);
 
@@ -876,11 +797,7 @@ TEST_F(MasterTest, ShutdownUnregisteredE
   driver.stop();
   driver.join();
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown(); // Must shutdown before 'isolator' gets deallocated.
 }
 
 
@@ -888,21 +805,14 @@ TEST_F(MasterTest, MasterInfo)
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
-
-  TestingIsolator isolator;
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  Try<PID<Slave> > slave = cluster.slaves.start();
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   Future<MasterInfo> masterInfo;
   EXPECT_CALL(sched, registered(&driver, _, _))
@@ -914,17 +824,13 @@ TEST_F(MasterTest, MasterInfo)
   driver.start();
 
   AWAIT_UNTIL(masterInfo);
-  EXPECT_EQ(master.port, masterInfo.get().port());
-  EXPECT_EQ(master.ip, masterInfo.get().ip());
+  EXPECT_EQ(master.get().port, masterInfo.get().port());
+  EXPECT_EQ(master.get().ip, masterInfo.get().ip());
 
   driver.stop();
   driver.join();
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown();
 }
 
 
@@ -932,21 +838,14 @@ TEST_F(MasterTest, MasterInfoOnReElectio
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
-  TestingIsolator isolator;
-
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  Try<PID<Slave> > slave = cluster.slaves.start();
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -966,7 +865,7 @@ TEST_F(MasterTest, MasterInfoOnReElectio
   // Simulate a spurious newMasterDetected event (e.g., due to ZooKeeper
   // expiration) at the scheduler.
   NewMasterDetectedMessage newMasterDetectedMsg;
-  newMasterDetectedMsg.set_pid(master);
+  newMasterDetectedMsg.set_pid(master.get());
 
   Future<MasterInfo> masterInfo;
   EXPECT_CALL(sched, reregistered(&driver, _))
@@ -975,17 +874,13 @@ TEST_F(MasterTest, MasterInfoOnReElectio
   process::post(message.get().to, newMasterDetectedMsg);
 
   AWAIT_UNTIL(masterInfo);
-  EXPECT_EQ(master.port, masterInfo.get().port());
-  EXPECT_EQ(master.ip, masterInfo.get().ip());
+  EXPECT_EQ(master.get().port, masterInfo.get().port());
+  EXPECT_EQ(master.get().ip, masterInfo.get().ip());
 
   driver.stop();
   driver.join();
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown();
 }
 
 
@@ -1014,23 +909,16 @@ TEST_F(WhitelistTest, WhitelistSlave)
   string hosts = hostname.get() + "\n" + "dummy-slave";
   ASSERT_SOME(os::write(path, hosts)) << "Error writing whitelist";
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  master::Flags masterFlags;
-  masterFlags.whitelist = "file://" + path;
-  Master m(&a, &files, masterFlags);
-  PID<Master> master = process::spawn(&m);
-
-  TestingIsolator isolator;
-
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
+  master::Flags flags = cluster.masters.flags;
+  flags.whitelist = "file://" + path;
+  Try<PID<Master> > master = cluster.masters.start(flags);
+  ASSERT_SOME(master);
 
-  BasicMasterDetector detector(master, slave, true);
+  Try<PID<Slave> > slave = cluster.slaves.start();
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -1046,11 +934,7 @@ TEST_F(WhitelistTest, WhitelistSlave)
   driver.stop();
   driver.join();
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown();
 }
 
 
@@ -1058,21 +942,14 @@ TEST_F(MasterTest, MasterLost)
 {
   ASSERT_TRUE(GTEST_IS_THREADSAFE);
 
-  HierarchicalDRFAllocatorProcess allocator;
-  Allocator a(&allocator);
-  Files files;
-  Master m(&a, &files);
-  PID<Master> master = process::spawn(&m);
-
-  TestingIsolator isolator;
+  Try<PID<Master> > master = cluster.masters.start();
+  ASSERT_SOME(master);
 
-  Slave s(slaveFlags, true, &isolator, &files);
-  PID<Slave> slave = process::spawn(&s);
-
-  BasicMasterDetector detector(master, slave, true);
+  Try<PID<Slave> > slave = cluster.slaves.start();
+  ASSERT_SOME(slave);
 
   MockScheduler sched;
-  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master);
+  MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get());
 
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
@@ -1094,17 +971,12 @@ TEST_F(MasterTest, MasterLost)
     .WillOnce(FutureSatisfy(&disconnected));
 
   // Simulate a spurious noMasterDetected event at the scheduler.
-  NoMasterDetectedMessage noMasterDetectedMsg;
-  process::post(message.get().to, noMasterDetectedMsg);
+  process::post(message.get().to, NoMasterDetectedMessage());
 
   AWAIT_UNTIL(disconnected);
 
   driver.stop();
   driver.join();
 
-  process::terminate(slave);
-  process::wait(slave);
-
-  process::terminate(master);
-  process::wait(master);
+  cluster.shutdown();
 }

Modified: incubator/mesos/trunk/src/tests/state_tests.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/state_tests.cpp?rev=1464756&r1=1464755&r2=1464756&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/state_tests.cpp (original)
+++ incubator/mesos/trunk/src/tests/state_tests.cpp Thu Apr  4 20:57:58 2013
@@ -47,7 +47,6 @@
 using namespace mesos;
 using namespace mesos::internal;
 using namespace mesos::internal::state;
-using namespace mesos::internal::tests;
 
 using namespace process;
 
@@ -261,7 +260,7 @@ TEST_F(LevelDBStateTest, Names)
 
 
 #ifdef MESOS_HAS_JAVA
-class ZooKeeperStateTest : public ZooKeeperTest
+class ZooKeeperStateTest : public tests::ZooKeeperTest
 {
 public:
   ZooKeeperStateTest()

Modified: incubator/mesos/trunk/src/tests/utils.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/utils.hpp?rev=1464756&r1=1464755&r2=1464756&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/utils.hpp (original)
+++ incubator/mesos/trunk/src/tests/utils.hpp Thu Apr  4 20:57:58 2013
@@ -69,7 +69,9 @@
 #include "slave/slave.hpp"
 #include "slave/state.hpp"
 
+#include "tests/cluster.hpp"
 #include "tests/flags.hpp"
+#include "tests/isolator.hpp"
 
 namespace mesos {
 namespace internal {
@@ -148,6 +150,40 @@ protected:
 };
 
 
+class MesosClusterTest : public ::testing::Test
+{
+protected:
+  virtual void SetUp()
+  {
+    // Create a temporary directory for the test.
+    Try<std::string> directory = mkdtemp();
+
+    CHECK(directory.isSome())
+      << "Failed to create temporary directory: " << directory.error();
+
+    cluster.slaves.flags.work_dir = directory.get();
+    cluster.slaves.flags.launcher_dir =
+      path::join(tests::flags.build_dir, "src");
+
+    // For locating killtree.sh.
+    os::setenv("MESOS_SOURCE_DIR", tests::flags.source_dir);
+
+    cluster.slaves.flags.resources =
+      Option<std::string>("cpus:2;mem:1024;disk:1024;ports:[31000-32000]");
+  }
+
+  virtual void TearDown()
+  {
+    os::rmdir(cluster.slaves.flags.work_dir);
+
+    os::unsetenv("MESOS_SOURCE_DIR");
+  }
+
+  Cluster cluster;
+};
+
+
+
 template <typename T>
 class IsolatorTest : public MesosTest
 {};
@@ -763,145 +799,6 @@ ACTION_P(SendStatusUpdateFromTaskID, sta
 #define AWAIT_UNTIL(future)                     \
   AWAIT_FOR(future, Seconds(2))
 
-
-class TestingIsolator : public slave::Isolator
-{
-public:
-  TestingIsolator()
-  {
-    setup();
-  }
-
-  TestingIsolator(const std::map<ExecutorID, Executor*>& _executors)
-    : executors(_executors)
-  {
-    setup();
-  }
-
-  TestingIsolator(const ExecutorID& executorId, Executor* executor)
-  {
-    executors[executorId] = executor;
-    setup();
-  }
-
-  virtual ~TestingIsolator() {}
-
-  virtual void initialize(
-      const slave::Flags& flags,
-      const Resources& resources,
-      bool local,
-      const process::PID<slave::Slave>& _slave)
-  {
-    slave = _slave;
-  }
-
-  virtual void launchExecutor(
-      const SlaveID& slaveId,
-      const FrameworkID& frameworkId,
-      const FrameworkInfo& frameworkInfo,
-      const ExecutorInfo& executorInfo,
-      const UUID& uuid,
-      const std::string& directory,
-      const Resources& resources,
-      const Option<std::string>& path)
-  {
-    if (executors.count(executorInfo.executor_id()) > 0) {
-      Executor* executor = executors[executorInfo.executor_id()];
-      MesosExecutorDriver* driver = new MesosExecutorDriver(executor);
-      drivers[executorInfo.executor_id()] = driver;
-
-      directories[executorInfo.executor_id()] = directory;
-
-      os::setenv("MESOS_LOCAL", "1");
-      os::setenv("MESOS_DIRECTORY", directory);
-      os::setenv("MESOS_SLAVE_PID", slave);
-      os::setenv("MESOS_SLAVE_ID", slaveId.value());
-      os::setenv("MESOS_FRAMEWORK_ID", frameworkId.value());
-      os::setenv("MESOS_EXECUTOR_ID", executorInfo.executor_id().value());
-      os::setenv("MESOS_CHECKPOINT", frameworkInfo.checkpoint() ? "1" : "0");
-
-      driver->start();
-
-      os::unsetenv("MESOS_LOCAL");
-      os::unsetenv("MESOS_DIRECTORY");
-      os::unsetenv("MESOS_SLAVE_PID");
-      os::unsetenv("MESOS_SLAVE_ID");
-      os::unsetenv("MESOS_FRAMEWORK_ID");
-      os::unsetenv("MESOS_EXECUTOR_ID");
-      os::unsetenv("MESOS_CHECKPOINT");
-
-      process::dispatch(
-          slave,
-          &slave::Slave::executorStarted,
-          frameworkId,
-          executorInfo.executor_id(),
-          -1);
-
-    } else {
-      FAIL() << "Cannot launch executor";
-    }
-  }
-
-  virtual void killExecutor(
-      const FrameworkID& frameworkId,
-      const ExecutorID& executorId)
-  {
-    if (drivers.count(executorId) > 0) {
-      MesosExecutorDriver* driver = drivers[executorId];
-      driver->stop();
-      driver->join();
-      delete driver;
-      drivers.erase(executorId);
-
-      process::dispatch(
-          slave,
-          &slave::Slave::executorTerminated,
-          frameworkId,
-          executorId,
-          0,
-          false,
-          "Killed executor");
-    } else {
-      FAIL() << "Cannot kill executor";
-    }
-  }
-
-  // Mocked so tests can check that the resources reflect all started tasks.
-  MOCK_METHOD3(resourcesChanged, void(const FrameworkID&,
-                                      const ExecutorID&,
-                                      const Resources&));
-
-  MOCK_METHOD2(
-      usage,
-      process::Future<ResourceStatistics>(
-          const FrameworkID&,
-          const ExecutorID&));
-
-  MOCK_METHOD1(
-      recover,
-      process::Future<Nothing>(const Option<slave::state::SlaveState>&));
-
-  std::map<ExecutorID, std::string> directories;
-
-private:
-  // Helper to setup default expectations.
-  void setup()
-  {
-    EXPECT_CALL(*this, resourcesChanged(testing::_, testing::_, testing::_))
-      .Times(testing::AnyNumber());
-
-    EXPECT_CALL(*this, usage(testing::_, testing::_))
-      .WillRepeatedly(testing::Return(ResourceStatistics()));
-
-    EXPECT_CALL(*this, recover(testing::_))
-      .WillRepeatedly(testing::Return(Nothing()));
-  }
-
-  std::map<ExecutorID, Executor*> executors;
-  std::map<ExecutorID, MesosExecutorDriver*> drivers;
-  process::PID<slave::Slave> slave;
-};
-
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {