http://git-wip-us.apache.org/repos/asf/mesos/blob/96351372/src/tests/port_mapping_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/port_mapping_tests.cpp b/src/tests/port_mapping_tests.cpp
deleted file mode 100644
index 45ef97a..0000000
--- a/src/tests/port_mapping_tests.cpp
+++ /dev/null
@@ -1,2296 +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 <gmock/gmock.h>
-
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include <process/future.hpp>
-#include <process/io.hpp>
-#include <process/reap.hpp>
-#include <process/subprocess.hpp>
-
-#include <stout/bytes.hpp>
-#include <stout/gtest.hpp>
-#include <stout/ip.hpp>
-#include <stout/json.hpp>
-#include <stout/mac.hpp>
-#include <stout/net.hpp>
-#include <stout/stopwatch.hpp>
-
-#include <stout/os/stat.hpp>
-#include <stout/os/exists.hpp>
-
-#include "linux/fs.hpp"
-
-#include "linux/routing/utils.hpp"
-
-#include "linux/routing/filter/ip.hpp"
-
-#include "linux/routing/link/link.hpp"
-
-#include "linux/routing/queueing/ingress.hpp"
-
-#include "master/master.hpp"
-
-#include "mesos/mesos.hpp"
-
-#include "slave/flags.hpp"
-#include "slave/slave.hpp"
-
-#include "slave/containerizer/isolators/network/port_mapping.hpp"
-
-#include "slave/containerizer/fetcher.hpp"
-#include "slave/containerizer/launcher.hpp"
-#include "slave/containerizer/linux_launcher.hpp"
-
-#include "slave/containerizer/mesos/containerizer.hpp"
-#include "slave/containerizer/mesos/launch.hpp"
-
-#include "tests/flags.hpp"
-#include "tests/mesos.hpp"
-#include "tests/utils.hpp"
-
-using namespace mesos::internal::slave;
-
-using namespace process;
-
-using namespace routing;
-using namespace routing::filter;
-using namespace routing::queueing;
-
-using mesos::internal::master::Master;
-
-using mesos::slave::Isolator;
-
-using std::list;
-using std::ostringstream;
-using std::set;
-using std::string;
-using std::vector;
-
-using testing::_;
-using testing::Eq;
-using testing::Return;
-
-namespace mesos {
-namespace internal {
-namespace tests {
-
-
-// An old glibc might not have this symbol.
-#ifndef MNT_DETACH
-#define MNT_DETACH 2
-#endif
-
-
-// Each test container works with a common specification of 2 CPUs,
-// 1GB of memory and 1GB of disk space, which experience has shown
-// to be sufficient to not encounter resource starvation issues when
-// running the test suite.
-const char* const containerCPU = "cpus:2";
-const char* const containerMemory = "mem:1024";
-const char* const containerDisk = "disk:1024";
-
-// We configure ephemeral and persistent port ranges outside the
-// default linux ip_local_port_range [32768-61000] in order to reduce
-// the probability of a conflict which could result in spurious
-// results (positive or negative) from these tests.
-const char* const ephemeralPorts = "ephemeral_ports:[30001-30999]";
-const char* const persistentPorts = "ports:[31000-32000]";
-
-// To keep things simple, we used fixed port ranges for our containers
-// in these tests rather than try to dynamically track port usage.
-// Note that container ports must be contained in the persistent port
-// range.
-const char* const container1Ports = "ports:[31000-31499]";
-const char* const container2Ports = "ports:[31500-32000]";
-
-// We define a validPort in the container1 assigned range which can
-// therefore accept incoming traffic.
-const int validPort = 31001;
-
-// We also define a port outside the persistent port range; containers
-// connecting to this port will never receive incoming traffic.
-const int invalidPort = 32502;
-
-
-static void cleanup(const string& eth0, const string& lo)
-{
-  // Clean up the ingress qdisc on eth0 and lo if exists.
-  Try<bool> hostEth0ExistsQdisc = ingress::exists(eth0);
-  ASSERT_SOME(hostEth0ExistsQdisc);
-
-  if (hostEth0ExistsQdisc.get()) {
-    ASSERT_SOME_TRUE(ingress::remove(eth0));
-  }
-
-  Try<bool> hostLoExistsQdisc = ingress::exists(lo);
-  ASSERT_SOME(hostLoExistsQdisc);
-
-  if (hostLoExistsQdisc.get()) {
-    ASSERT_SOME_TRUE(ingress::remove(lo));
-  }
-
-  // Clean up all 'veth' devices if exist.
-  Try<set<string> > links = net::links();
-  ASSERT_SOME(links);
-
-  foreach (const string& name, links.get()) {
-    if (strings::startsWith(name, slave::PORT_MAPPING_VETH_PREFIX())) {
-      ASSERT_SOME_TRUE(link::remove(name));
-    }
-  }
-
-  Try<list<string> > entries = os::ls(slave::PORT_MAPPING_BIND_MOUNT_ROOT());
-  ASSERT_SOME(entries);
-
-  foreach (const string& file, entries.get()) {
-    string target = path::join(slave::PORT_MAPPING_BIND_MOUNT_ROOT(), file);
-
-    // NOTE: Here, we ignore the unmount errors because previous tests
-    // may have created the file and died before mounting.
-    if (!os::stat::islink(target)) {
-      mesos::internal::fs::unmount(target, MNT_DETACH);
-    }
-
-    // Remove the network namespace handle and the corresponding
-    // symlinks. The removal here is best effort.
-    os::rm(target);
-  }
-}
-
-
-class PortMappingIsolatorTest : public TemporaryDirectoryTest
-{
-public:
-  static void SetUpTestCase()
-  {
-    ASSERT_SOME(routing::check())
-      << "-------------------------------------------------------------\n"
-      << "We cannot run any PortMappingIsolatorTests because your\n"
-      << "libnl library is not new enough. You can either install a\n"
-      << "new libnl library, or disable this test case\n"
-      << "-------------------------------------------------------------";
-
-    ASSERT_SOME_EQ(0, os::shell(NULL, "which nc"))
-      << "-------------------------------------------------------------\n"
-      << "We cannot run any PortMappingIsolatorTests because 'nc'\n"
-      << "could not be found. You can either install 'nc', or disable\n"
-      << "this test case\n"
-      << "-------------------------------------------------------------";
-
-    ASSERT_SOME_EQ(0, os::shell(NULL, "which arping"))
-      << "-------------------------------------------------------------\n"
-      << "We cannot run some PortMappingIsolatorTests because 'arping'\n"
-      << "could not be found. You can either isntall 'arping', or\n"
-      << "disable this test case\n"
-      << "-------------------------------------------------------------";
-  }
-
-  PortMappingIsolatorTest() : hostIP(net::IP(INADDR_ANY)) {}
-
-protected:
-  virtual void SetUp()
-  {
-    TemporaryDirectoryTest::SetUp();
-
-    flags = CreateSlaveFlags();
-
-    // Guess the name of the public interface.
-    Result<string> _eth0 = link::eth0();
-    ASSERT_SOME(_eth0) << "Failed to guess the name of the public interface";
-
-    eth0 = _eth0.get();
-
-    LOG(INFO) << "Using " << eth0 << " as the public interface";
-
-    // Guess the name of the loopback interface.
-    Result<string> _lo = link::lo();
-    ASSERT_SOME(_lo) << "Failed to guess the name of the loopback interface";
-
-    lo = _lo.get();
-
-    LOG(INFO) << "Using " << lo << " as the loopback interface";
-
-    // Clean up qdiscs and veth devices.
-    cleanup(eth0, lo);
-
-    // Get host IP address.
-    Result<net::IPNetwork> hostIPNetwork =
-        net::IPNetwork::fromLinkDevice(eth0, AF_INET);
-
-    CHECK_SOME(hostIPNetwork)
-      << "Failed to retrieve the host public IP network from " << eth0 << ": "
-      << hostIPNetwork.error();
-
-    hostIP = hostIPNetwork.get().address();
-
-    // Get all the external name servers for tests that need to talk
-    // to an external host, e.g., ping, DNS.
-    Try<string> read = os::read("/etc/resolv.conf");
-    CHECK_SOME(read);
-
-    foreach (const string& line, strings::split(read.get(), "\n")) {
-      if (!strings::startsWith(line, "nameserver")) {
-        continue;
-      }
-
-      vector<string> tokens = strings::split(line, " ");
-      ASSERT_EQ(2u, tokens.size()) << "Unexpected format in 
'/etc/resolv.conf'";
-      if (tokens[1] != "127.0.0.1") {
-        nameServers.push_back(tokens[1]);
-      }
-    }
-
-    container1Ready = path::join(os::getcwd(), "container1_ready");
-    container2Ready = path::join(os::getcwd(), "container2_ready");
-    trafficViaLoopback = path::join(os::getcwd(), "traffic_via_loopback");
-    trafficViaPublic = path::join(os::getcwd(), "traffic_via_public");
-    exitStatus = path::join(os::getcwd(), "exit_status");
-  }
-
-  virtual void TearDown()
-  {
-    cleanup(eth0, lo);
-    TemporaryDirectoryTest::TearDown();
-  }
-
-  slave::Flags CreateSlaveFlags()
-  {
-    slave::Flags flags;
-
-    flags.launcher_dir = path::join(tests::flags.build_dir, "src");
-
-    flags.resources = strings::join(";", vector<string>({
-        containerCPU,
-        containerMemory,
-        containerDisk,
-        ephemeralPorts,
-        persistentPorts }));
-
-    // NOTE: '16' should be enough for all our tests.
-    flags.ephemeral_ports_per_container = 16;
-
-    flags.isolation = "network/port_mapping";
-
-    return flags;
-  }
-
-  Try<pid_t> launchHelper(
-      Launcher* launcher,
-      int pipes[2],
-      const ContainerID& containerId,
-      const string& command,
-      const Option<CommandInfo>& preparation)
-  {
-    CommandInfo commandInfo;
-    commandInfo.set_value(command);
-
-    // The flags to pass to the helper process.
-    MesosContainerizerLaunch::Flags launchFlags;
-
-    launchFlags.command = JSON::Protobuf(commandInfo);
-    launchFlags.directory = os::getcwd();
-
-    CHECK_SOME(os::user());
-    launchFlags.user = os::user().get();
-
-    launchFlags.pipe_read = pipes[0];
-    launchFlags.pipe_write = pipes[1];
-
-    JSON::Object commands;
-    JSON::Array array;
-    array.values.push_back(JSON::Protobuf(preparation.get()));
-    commands.values["commands"] = array;
-
-    launchFlags.commands = commands;
-
-    vector<string> argv(2);
-    argv[0] = MESOS_CONTAINERIZER;
-    argv[1] = MesosContainerizerLaunch::NAME;
-
-    Try<pid_t> pid = launcher->fork(
-        containerId,
-        path::join(flags.launcher_dir, MESOS_CONTAINERIZER),
-        argv,
-        Subprocess::FD(STDIN_FILENO),
-        Subprocess::FD(STDOUT_FILENO),
-        Subprocess::FD(STDERR_FILENO),
-        launchFlags,
-        None(),
-        None());
-
-    return pid;
-  }
-
-  Result<ResourceStatistics> statisticsHelper(
-      pid_t pid,
-      bool enable_summary,
-      bool enable_details)
-  {
-    // Retrieve the socket information from inside the container.
-    PortMappingStatistics statistics;
-    statistics.flags.pid = pid;
-    statistics.flags.eth0_name = eth0;
-    statistics.flags.enable_socket_statistics_summary = enable_summary;
-    statistics.flags.enable_socket_statistics_details = enable_details;
-
-    vector<string> argv(2);
-    argv[0] = "mesos-network-helper";
-    argv[1] = PortMappingStatistics::NAME;
-
-    // We don't need STDIN; we need STDOUT for the result; we leave
-    // STDERR as is to log to slave process.
-    Try<Subprocess> s = subprocess(
-        path::join(flags.launcher_dir, "mesos-network-helper"),
-        argv,
-        Subprocess::PATH("/dev/null"),
-        Subprocess::PIPE(),
-        Subprocess::FD(STDERR_FILENO),
-        statistics.flags);
-
-    CHECK_SOME(s);
-
-    Future<Option<int> > status = s.get().status();
-    AWAIT_EXPECT_READY(status);
-    EXPECT_SOME_EQ(0, status.get());
-
-    Future<string> out = io::read(s.get().out().get());
-    AWAIT_EXPECT_READY(out);
-
-    Try<JSON::Object> object = JSON::parse<JSON::Object>(out.get());
-    CHECK_SOME(object);
-
-    return ::protobuf::parse<ResourceStatistics>(object.get());
-  }
-
-  slave::Flags flags;
-
-  // Name of the host eth0 and lo.
-  string eth0;
-  string lo;
-
-  // Host public IP network.
-  net::IP hostIP;
-
-  // All the external name servers as read from /etc/resolv.conf.
-  vector<string> nameServers;
-
-  // Some auxiliary files for the tests.
-  string container1Ready;
-  string container2Ready;
-  string trafficViaLoopback;
-  string trafficViaPublic;
-  string exitStatus;
-};
-
-
-// Wait up to timeout seconds for a file to be created. If timeout is
-// zero, then wait indefinitely. Return true if file exists.
-//
-// TODO(pbrett): Consider generalizing this function and moving it to
-// a common header.
-static bool waitForFileCreation(
-    const string& path,
-    const Duration& duration = Seconds(60))
-{
-  Stopwatch timer;
-  timer.start();
-  while (!os::exists(path)) {
-    if ((duration > Duration::zero()) && (timer.elapsed() > duration))
-      break;
-    os::sleep(Milliseconds(50));
-  }
-  return os::exists(path);
-}
-
-
-// This test uses two containers: one listens to 'validPort' and
-// 'invalidPort' and writes data received to files; the other
-// container attempts to connect to the previous container using
-// 'validPort' and 'invalidPort'. Verify that only the connection
-// through 'validPort' is successful by confirming that the expected
-// data has been written to its output file.
-TEST_F(PortMappingIsolatorTest, ROOT_NC_ContainerToContainerTCP)
-{
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId1;
-  containerId1.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir1 = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir1);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId1,
-        executorInfo,
-        dir1.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  ostringstream command1;
-
-  // Listen to 'localhost' and 'port'.
-  command1 << "nc -l localhost " << validPort << " > " << trafficViaLoopback
-           << "& ";
-
-  // Listen to 'public ip' and 'port'.
-  command1 << "nc -l " << hostIP << " " << validPort << " > "
-           << trafficViaPublic << "& ";
-
-  // Listen to 'invalidPort'.  This should not receive any data.
-  command1 << "nc -l " << invalidPort << " | tee " << trafficViaLoopback << " "
-           << trafficViaPublic << "& ";
-
-  // Touch the guard file.
-  command1 << "touch " << container1Ready;
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId1,
-      command1.str(),
-      preparation1.get());
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status1 = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId1, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to start.
-  ASSERT_TRUE(waitForFileCreation(container1Ready));
-
-  ContainerID containerId2;
-  containerId2.set_value("container2");
-
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container2Ports).get());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir2 = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir2);
-
-  Future<Option<CommandInfo> > preparation2 =
-    isolator.get()->prepare(
-        containerId2,
-        executorInfo,
-        dir2.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation2);
-  ASSERT_SOME(preparation2.get());
-
-  ostringstream command2;
-
-  // Send to 'localhost' and 'port'.
-  command2 << "printf hello1 | nc localhost " << validPort << ";";
-  // Send to 'localhost' and 'invalidPort'. This should fail.
-  command2 << "printf hello2 | nc localhost " << invalidPort << ";";
-  // Send to 'public IP' and 'port'.
-  command2 << "printf hello3 | nc " << hostIP << " " << validPort << ";";
-  // Send to 'public IP' and 'invalidPort'. This should fail.
-  command2 << "printf hello4 | nc " << hostIP << " " << invalidPort << ";";
-  // Touch the guard file.
-  command2 << "touch " << container2Ready;
-
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId2,
-      command2.str(),
-      preparation2.get());
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status2 = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId2, pid.get()));
-
-  // Now signal the child to continue.
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to start.
-  ASSERT_TRUE(waitForFileCreation(container2Ready));
-
-  // Wait for the command to complete.
-  AWAIT_READY(status1);
-  AWAIT_READY(status2);
-
-  EXPECT_SOME_EQ("hello1", os::read(trafficViaLoopback));
-  EXPECT_SOME_EQ("hello3", os::read(trafficViaPublic));
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId1));
-  AWAIT_READY(launcher.get()->destroy(containerId2));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId1));
-  AWAIT_READY(isolator.get()->cleanup(containerId2));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-// The same container-to-container test but with UDP.
-TEST_F(PortMappingIsolatorTest, ROOT_NC_ContainerToContainerUDP)
-{
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId1;
-  containerId1.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir1 = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir1);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId1,
-        executorInfo,
-        dir1.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  ostringstream command1;
-
-  // Listen to 'localhost' and 'port'.
-  command1 << "nc -u -l localhost " << validPort << " > " << trafficViaLoopback
-           << "& ";
-
-  // Listen to 'public ip' and 'port'.
-  command1 << "nc -u -l " << hostIP << " " << validPort << " > "
-           << trafficViaPublic << "& ";
-
-  // Listen to 'invalidPort'. This should not receive anything.
-  command1 << "nc -u -l " << invalidPort << " | tee " << trafficViaLoopback
-           << " " << trafficViaPublic << "& ";
-
-  // Touch the guard file.
-  command1 << "touch " << container1Ready;
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId1,
-      command1.str(),
-      preparation1.get());
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status1 = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId1, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to start.
-  ASSERT_TRUE(waitForFileCreation(container1Ready));
-
-  ContainerID containerId2;
-  containerId2.set_value("container2");
-
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container2Ports).get());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir2 = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir2);
-
-  Future<Option<CommandInfo> > preparation2 =
-    isolator.get()->prepare(
-        containerId2,
-        executorInfo,
-        dir2.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation2);
-  ASSERT_SOME(preparation2.get());
-
-  ostringstream command2;
-
-  // Send to 'localhost' and 'port'.
-  command2 << "printf hello1 | nc -w1 -u localhost " << validPort << ";";
-  // Send to 'localhost' and 'invalidPort'. No data should be sent.
-  command2 << "printf hello2 | nc -w1 -u localhost " << invalidPort << ";";
-  // Send to 'public IP' and 'port'.
-  command2 << "printf hello3 | nc -w1 -u " << hostIP << " " << validPort << 
";";
-  // Send to 'public IP' and 'invalidPort'. No data should be sent.
-  command2 << "printf hello4 | nc -w1 -u " << hostIP << " " << invalidPort
-           << ";";
-  // Touch the guard file.
-  command2 << "touch " << container2Ready;
-
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId2,
-      command2.str(),
-      preparation2.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status2 = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId2, pid.get()));
-
-  // Now signal the child to continue.
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to start.
-  ASSERT_TRUE(waitForFileCreation(container2Ready));
-
-  // Wait for the command to complete.
-  AWAIT_READY(status1);
-  AWAIT_READY(status2);
-
-  EXPECT_SOME_EQ("hello1", os::read(trafficViaLoopback));
-  EXPECT_SOME_EQ("hello3", os::read(trafficViaPublic));
-
-  AWAIT_READY(launcher.get()->destroy(containerId1));
-  AWAIT_READY(launcher.get()->destroy(containerId2));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId1));
-  AWAIT_READY(isolator.get()->cleanup(containerId2));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-// Test the scenario where a UDP server is in a container while host
-// tries to establish a UDP connection.
-TEST_F(PortMappingIsolatorTest, ROOT_NC_HostToContainerUDP)
-{
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId;
-  containerId.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId,
-        executorInfo,
-        dir.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  ostringstream command1;
-
-  // Listen to 'localhost' and 'Port'.
-  command1 << "nc -u -l localhost " << validPort << " > " << trafficViaLoopback
-           << "&";
-
-  // Listen to 'public IP' and 'Port'.
-  command1 << "nc -u -l " << hostIP << " " << validPort << " > "
-           << trafficViaPublic << "&";
-
-  // Listen to 'public IP' and 'invalidPort'. This should not receive anything.
-  command1 << "nc -u -l " << invalidPort << " | tee " << trafficViaLoopback
-           << " " << trafficViaPublic << "&";
-
-  // Touch the guard file.
-  command1 << "touch " << container1Ready;
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId,
-      command1.str(),
-      preparation1.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to start.
-  ASSERT_TRUE(waitForFileCreation(container1Ready));
-
-  // Send to 'localhost' and 'port'.
-  ostringstream command2;
-  command2 << "printf hello1 | nc -w1 -u localhost " << validPort;
-  ASSERT_SOME_EQ(0, os::shell(NULL, command2.str().c_str()));
-
-  // Send to 'localhost' and 'invalidPort'. The command should return
-  // successfully because UDP is stateless but no data could be sent.
-  ostringstream command3;
-  command3 << "printf hello2 | nc -w1 -u localhost " << invalidPort;
-  ASSERT_SOME_EQ(0, os::shell(NULL, command3.str().c_str()));
-
-  // Send to 'public IP' and 'port'.
-  ostringstream command4;
-  command4 << "printf hello3 | nc -w1 -u " << hostIP << " " << validPort;
-  ASSERT_SOME_EQ(0, os::shell(NULL, command4.str().c_str()));
-
-  // Send to 'public IP' and 'invalidPort'. The command should return
-  // successfully because UDP is stateless but no data could be sent.
-  ostringstream command5;
-  command5 << "printf hello4 | nc -w1 -u " << hostIP << " " << invalidPort;
-  ASSERT_SOME_EQ(0, os::shell(NULL, command5.str().c_str()));
-
-  EXPECT_SOME_EQ("hello1", os::read(trafficViaLoopback));
-  EXPECT_SOME_EQ("hello3", os::read(trafficViaPublic));
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-// Test the scenario where a TCP server is in a container while host
-// tries to establish a TCP connection.
-TEST_F(PortMappingIsolatorTest, ROOT_NC_HostToContainerTCP)
-{
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId;
-  containerId.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId,
-        executorInfo,
-        dir.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  ostringstream command1;
-
-  // Listen to 'localhost' and 'Port'.
-  command1 << "nc -l localhost " << validPort << " > " << trafficViaLoopback
-           << "&";
-
-  // Listen to 'public IP' and 'Port'.
-  command1 << "nc -l " << hostIP << " " << validPort << " > "
-           << trafficViaPublic << "&";
-
-  // Listen to 'public IP' and 'invalidPort'. This should fail.
-  command1 << "nc -l " << invalidPort << " | tee " << trafficViaLoopback << " "
-           << trafficViaPublic << "&";
-
-  // Touch the guard file.
-  command1 << "touch " << container1Ready;
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId,
-      command1.str(),
-      preparation1.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to start.
-  ASSERT_TRUE(waitForFileCreation(container1Ready));
-
-  // Send to 'localhost' and 'port'.
-  ostringstream command2;
-  command2 << "printf hello1 | nc localhost " << validPort;
-  ASSERT_SOME_EQ(0, os::shell(NULL, command2.str().c_str()));
-
-  // Send to 'localhost' and 'invalidPort'. This should fail because TCP
-  // connection couldn't be established..
-  ostringstream command3;
-  command3 << "printf hello2 | nc localhost " << invalidPort;
-  ASSERT_SOME_EQ(256, os::shell(NULL, command3.str().c_str()));
-
-  // Send to 'public IP' and 'port'.
-  ostringstream command4;
-  command4 << "printf hello3 | nc " << hostIP << " " << validPort;
-  ASSERT_SOME_EQ(0, os::shell(NULL, command4.str().c_str()));
-
-  // Send to 'public IP' and 'invalidPort'. This should fail because TCP
-  // connection couldn't be established.
-  ostringstream command5;
-  command5 << "printf hello4 | nc " << hostIP << " " << invalidPort;
-  ASSERT_SOME_EQ(256, os::shell(NULL, command5.str().c_str()));
-
-  EXPECT_SOME_EQ("hello1", os::read(trafficViaLoopback));
-  EXPECT_SOME_EQ("hello3", os::read(trafficViaPublic));
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-// Test the scenario where a container issues ICMP requests to
-// external hosts.
-TEST_F(PortMappingIsolatorTest, ROOT_ContainerICMPExternal)
-{
-  // TODO(chzhcn): Even though this is unlikely, consider a better
-  // way to get external servers.
-  ASSERT_FALSE(nameServers.empty())
-    << "-------------------------------------------------------------\n"
-    << "We cannot run some PortMappingIsolatorTests because we could\n"
-    << "not find any external name servers in /etc/resolv.conf.\n"
-    << "-------------------------------------------------------------";
-
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId;
-  containerId.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId,
-        executorInfo,
-        dir.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  ostringstream command1;
-  for (unsigned int i = 0; i < nameServers.size(); i++) {
-    const string& IP = nameServers[i];
-    command1 << "ping -c1 " << IP;
-    if (i + 1 < nameServers.size()) {
-      command1 << " && ";
-    }
-  }
-  command1 << "; printf $? > " << exitStatus << "; sync";
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId,
-      command1.str(),
-      preparation1.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to complete.
-  AWAIT_READY(status);
-
-  EXPECT_SOME_EQ("0", os::read(exitStatus));
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-// Test the scenario where a container issues ICMP requests to itself.
-TEST_F(PortMappingIsolatorTest, ROOT_ContainerICMPInternal)
-{
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId;
-  containerId.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId,
-        executorInfo,
-        dir.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  ostringstream command1;
-  command1 << "ping -c1 127.0.0.1 && ping -c1 " << hostIP
-           << "; printf $? > " << exitStatus << "; sync";
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId,
-      command1.str(),
-      preparation1.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to complete.
-  AWAIT_READY(status);
-
-  EXPECT_SOME_EQ("0", os::read(exitStatus));
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-// Test the scenario where a container issues ARP requests to
-// external hosts.
-TEST_F(PortMappingIsolatorTest, ROOT_ContainerARPExternal)
-{
-  // TODO(chzhcn): Even though this is unlikely, consider a better
-  // way to get external servers.
-  ASSERT_FALSE(nameServers.empty())
-    << "-------------------------------------------------------------\n"
-    << "We cannot run some PortMappingIsolatorTests because we could\n"
-    << "not find any external name servers in /etc/resolv.conf.\n"
-    << "-------------------------------------------------------------";
-
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId;
-  containerId.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId,
-        executorInfo,
-        dir.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  ostringstream command1;
-  for (unsigned int i = 0; i < nameServers.size(); i++) {
-    const string& IP = nameServers[i];
-    // Time out after 1s and terminate upon receiving the first reply.
-    command1 << "arping -f -w1 " << IP << " -I " << eth0;
-    if (i + 1 < nameServers.size()) {
-      command1 << " && ";
-    }
-  }
-  command1 << "; printf $? > " << exitStatus << "; sync";
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId,
-      command1.str(),
-      preparation1.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to complete.
-  AWAIT_READY(status);
-
-  EXPECT_SOME_EQ("0", os::read(exitStatus));
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-// Test DNS connectivity.
-TEST_F(PortMappingIsolatorTest, ROOT_DNS)
-{
-  // TODO(chzhcn): Even though this is unlikely, consider a better
-  // way to get external servers.
-  ASSERT_FALSE(nameServers.empty())
-    << "-------------------------------------------------------------\n"
-    << "We cannot run some PortMappingIsolatorTests because we could\n"
-    << "not find any external name servers in /etc/resolv.conf.\n"
-    << "-------------------------------------------------------------";
-
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId;
-  containerId.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId,
-        executorInfo,
-        dir.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  ostringstream command1;
-  for (unsigned int i = 0; i < nameServers.size(); i++) {
-    const string& IP = nameServers[i];
-    command1 << "host " << IP;
-    if (i + 1 < nameServers.size()) {
-      command1 << " && ";
-    }
-  }
-  command1 << "; printf $? > " << exitStatus << "; sync";
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId,
-      command1.str(),
-      preparation1.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to complete.
-  AWAIT_READY(status);
-
-  EXPECT_SOME_EQ("0", os::read(exitStatus));
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-// Test the scenario where a container has run out of ephemeral ports
-// to use.
-TEST_F(PortMappingIsolatorTest, ROOT_TooManyContainers)
-{
-  // Increase the ephemeral ports per container so that we dont have
-  // enough ephemeral ports to launch a second container.
-  flags.ephemeral_ports_per_container = 512;
-
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId1;
-  containerId1.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir1 = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir1);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId1,
-        executorInfo,
-        dir1.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  ostringstream command1;
-  command1 << "sleep 1000";
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId1,
-      command1.str(),
-      preparation1.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > status1 = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId1, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  ContainerID containerId2;
-  containerId2.set_value("container2");
-
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container2Ports).get());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir2 = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir2);
-
-  Future<Option<CommandInfo> > preparation2 =
-    isolator.get()->prepare(
-        containerId2,
-        executorInfo,
-        dir2.get(),
-        None(),
-        None());
-
-  AWAIT_FAILED(preparation2);
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId1));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId1));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-// Test the scenario where PortMappingIsolator uses a very small
-// egress rate limit.
-TEST_F(PortMappingIsolatorTest, ROOT_NC_SmallEgressLimit)
-{
-  // Note that the underlying rate limiting mechanism usually has a
-  // small allowance for burst. Empirically, as least 10x of the rate
-  // limit amount of data is required to make sure the burst is an
-  // insignificant factor of the transmission time.
-
-  // To-be-tested egress rate limit, in Bytes/s.
-  const Bytes rate = 2000;
-  // Size of the data to send, in Bytes.
-  const Bytes size = 20480;
-
-  // Use a very small egress limit.
-  flags.egress_rate_limit_per_container = rate;
-
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Open an nc server on the host side. Note that 'invalidPort' is in
-  // neither 'ports' nor 'ephemeral_ports', which makes it a good port
-  // to use on the host.
-  ostringstream command1;
-  command1 << "nc -l localhost " << invalidPort << " > /devnull";
-  Try<Subprocess> s = subprocess(command1.str().c_str());
-  CHECK_SOME(s);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId;
-  containerId.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId,
-        executorInfo,
-        dir.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  // Fill 'size' bytes of data. The actual content does not matter.
-  string data(size.bytes(), 'a');
-
-  ostringstream command2;
-  const string transmissionTime = path::join(os::getcwd(), 
"transmission_time");
-
-  command2 << "echo 'Sending " << size.bytes()
-           << " bytes of data under egress rate limit " << rate.bytes()
-           << "Bytes/s...';";
-
-  command2 << "{ time -p echo " << data  << " | nc localhost "
-           << invalidPort << " ; } 2> " << transmissionTime << " && ";
-
-  // Touch the guard file.
-  command2 << "touch " << container1Ready;
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId,
-      command2.str(),
-      preparation1.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > reap = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Wait for the command to finish.
-  ASSERT_TRUE(waitForFileCreation(container1Ready));
-
-  Try<string> read = os::read(transmissionTime);
-  CHECK_SOME(read);
-
-  // Get the real elapsed time from `time` output. Sample output:
-  // real 12.37
-  // user 0.00
-  // sys 0.00
-  vector<string> lines = strings::split(strings::trim(read.get()), "\n");
-  ASSERT_EQ(3u, lines.size());
-
-  vector<string> split = strings::split(lines[0], " ");
-  ASSERT_EQ(2u, split.size());
-
-  Try<float> time = numify<float>(split[1]);
-  ASSERT_SOME(time);
-  ASSERT_GT(time.get(), (size.bytes() / rate.bytes()));
-
-  // Make sure the nc server exits normally.
-  Future<Option<int> > status = s.get().status();
-  AWAIT_READY(status);
-  EXPECT_SOME_EQ(0, status.get());
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-bool HasTCPSocketsCount(const ResourceStatistics& statistics)
-{
-  return statistics.has_net_tcp_active_connections() &&
-    statistics.has_net_tcp_time_wait_connections();
-}
-
-
-bool HasTCPSocketsRTT(const ResourceStatistics& statistics)
-{
-  // We either have all of the following metrics or we have nothing.
-  if (statistics.has_net_tcp_rtt_microsecs_p50() &&
-      statistics.has_net_tcp_rtt_microsecs_p90() &&
-      statistics.has_net_tcp_rtt_microsecs_p95() &&
-      statistics.has_net_tcp_rtt_microsecs_p99()) {
-    return true;
-  } else {
-    return false;
-  }
-}
-
-
-// Test that RTT can be returned properly from usage(). This test is
-// very similar to SmallEgressLimitTest in its setup.
-TEST_F(PortMappingIsolatorTest, ROOT_NC_PortMappingStatistics)
-{
-  // To-be-tested egress rate limit, in Bytes/s.
-  const Bytes rate = 2000;
-  // Size of the data to send, in Bytes.
-  const Bytes size = 20480;
-
-  // Use a very small egress limit.
-  flags.egress_rate_limit_per_container = rate;
-  flags.network_enable_socket_statistics_summary = true;
-  flags.network_enable_socket_statistics_details = true;
-
-  Try<Isolator*> isolator = PortMappingIsolatorProcess::create(flags);
-  CHECK_SOME(isolator);
-
-  Try<Launcher*> launcher =
-    LinuxLauncher::create(flags, isolator.get()->namespaces().get());
-  CHECK_SOME(launcher);
-
-  // Open an nc server on the host side. Note that 'invalidPort' is
-  // in neither 'ports' nor 'ephemeral_ports', which makes it a good
-  // port to use on the host. We use this host's public IP because
-  // connections to the localhost IP are filtered out when retrieving
-  // the RTT information inside containers.
-  ostringstream command1;
-  command1 << "nc -l " << hostIP << " " << invalidPort << " > /devnull";
-  Try<Subprocess> s = subprocess(command1.str().c_str());
-  CHECK_SOME(s);
-
-  // Set the executor's resources.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse(container1Ports).get());
-
-  ContainerID containerId;
-  containerId.set_value("container1");
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir1 = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir1);
-
-  Future<Option<CommandInfo> > preparation1 =
-    isolator.get()->prepare(
-        containerId,
-        executorInfo,
-        dir1.get(),
-        None(),
-        None());
-
-  AWAIT_READY(preparation1);
-  ASSERT_SOME(preparation1.get());
-
-  // Fill 'size' bytes of data. The actual content does not matter.
-  string data(size.bytes(), 'a');
-
-  ostringstream command2;
-  const string transmissionTime = path::join(os::getcwd(), 
"transmission_time");
-
-  command2 << "echo 'Sending " << size.bytes()
-           << " bytes of data under egress rate limit " << rate.bytes()
-           << "Bytes/s...';";
-
-  command2 << "{ time -p echo " << data  << " | nc " << hostIP << " "
-           << invalidPort << " ; } 2> " << transmissionTime << " && ";
-
-  // Touch the guard file.
-  command2 << "touch " << container1Ready;
-
-  int pipes[2];
-  ASSERT_NE(-1, ::pipe(pipes));
-
-  Try<pid_t> pid = launchHelper(
-      launcher.get(),
-      pipes,
-      containerId,
-      command2.str(),
-      preparation1.get());
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int> > reap = process::reap(pid.get());
-
-  // Continue in the parent.
-  ::close(pipes[0]);
-
-  // Isolate the forked child.
-  AWAIT_READY(isolator.get()->isolate(containerId, pid.get()));
-
-  // Now signal the child to continue.
-  char dummy;
-  ASSERT_LT(0, ::write(pipes[1], &dummy, sizeof(dummy)));
-  ::close(pipes[1]);
-
-  // Test that RTT can be returned while transmission is going. It is
-  // possible that the first few statistics returned don't have a RTT
-  // value because it takes a few round-trips to actually establish a
-  // tcp connection and start sending data. Nevertheless, we should
-  // see a meaningful result well within seconds.
-  Duration waited = Duration::zero();
-  do {
-    os::sleep(Milliseconds(200));
-    waited += Milliseconds(200);
-
-    // Do an end-to-end test by calling `usage`.
-    Future<ResourceStatistics> usage = isolator.get()->usage(containerId);
-    AWAIT_READY(usage);
-
-    if (usage.get().has_net_tcp_rtt_microsecs_p50() &&
-        usage.get().has_net_tcp_active_connections()) {
-      EXPECT_GT(usage.get().net_tcp_active_connections(), 0);
-      break;
-    }
-  } while (waited < Seconds(5));
-  ASSERT_LT(waited, Seconds(5));
-
-  // While the connection is still active, try out different flag
-  // combinations.
-  Result<ResourceStatistics> statistics =
-      statisticsHelper(pid.get(), true, true);
-  ASSERT_SOME(statistics);
-  EXPECT_TRUE(HasTCPSocketsCount(statistics.get()));
-  EXPECT_TRUE(HasTCPSocketsRTT(statistics.get()));
-
-  statistics = statisticsHelper(pid.get(), true, false);
-  ASSERT_SOME(statistics);
-  EXPECT_TRUE(HasTCPSocketsCount(statistics.get()));
-  EXPECT_FALSE(HasTCPSocketsRTT(statistics.get()));
-
-  statistics = statisticsHelper(pid.get(), false, true);
-  ASSERT_SOME(statistics);
-  EXPECT_FALSE(HasTCPSocketsCount(statistics.get()));
-  EXPECT_TRUE(HasTCPSocketsRTT(statistics.get()));
-
-  statistics = statisticsHelper(pid.get(), false, false);
-  ASSERT_SOME(statistics);
-  EXPECT_FALSE(HasTCPSocketsCount(statistics.get()));
-  EXPECT_FALSE(HasTCPSocketsRTT(statistics.get()));
-
-  // Wait for the command to finish.
-  ASSERT_TRUE(waitForFileCreation(container1Ready));
-
-  // Make sure the nc server exits normally.
-  Future<Option<int> > status = s.get().status();
-  AWAIT_READY(status);
-  EXPECT_SOME_EQ(0, status.get());
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator.get()->cleanup(containerId));
-
-  delete isolator.get();
-  delete launcher.get();
-}
-
-
-class PortMappingMesosTest : public ContainerizerTest<MesosContainerizer>
-{
-public:
-  virtual void SetUp()
-  {
-    ContainerizerTest<MesosContainerizer>::SetUp();
-
-    // Guess the name of the public interface.
-    Result<string> _eth0 = link::eth0();
-    ASSERT_SOME(_eth0) << "Failed to guess the name of the public interface";
-
-    eth0 = _eth0.get();
-
-    LOG(INFO) << "Using " << eth0 << " as the public interface";
-
-    // Guess the name of the loopback interface.
-    Result<string> _lo = link::lo();
-    ASSERT_SOME(_lo) << "Failed to guess the name of the loopback interface";
-
-    lo = _lo.get();
-
-    LOG(INFO) << "Using " << lo << " as the loopback interface";
-
-    cleanup(eth0, lo);
-  }
-
-  virtual void TearDown()
-  {
-    cleanup(eth0, lo);
-
-    ContainerizerTest<MesosContainerizer>::TearDown();
-  }
-
-  Fetcher fetcher;
-
-  // Name of the host eth0 and lo.
-  string eth0;
-  string lo;
-};
-
-
-// Test the scenario where the network isolator is asked to recover
-// both types of containers: containers that were previously managed
-// by network isolator, and containers that weren't.
-TEST_F(PortMappingMesosTest, CGROUPS_ROOT_RecoverMixedContainers)
-{
-  master::Flags masterFlags = CreateMasterFlags();
-
-  Try<PID<Master>> master = StartMaster(masterFlags);
-  ASSERT_SOME(master);
-
-  // Start the first slave without the network isolator.
-  slave::Flags slaveFlags = CreateSlaveFlags();
-
-  // NOTE: This is to make sure that we use the linux launcher which
-  // is consistent with the launchers we use for other containerizers
-  // we create in this test. Also, this will bypass MESOS-2554.
-  slaveFlags.isolation = "cgroups/cpu,cgroups/mem";
-
-  Try<MesosContainerizer*> containerizer1 =
-    MesosContainerizer::create(slaveFlags, true, &fetcher);
-
-  ASSERT_SOME(containerizer1);
-
-  Try<PID<Slave> > slave = StartSlave(containerizer1.get(), slaveFlags);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-
-  // Enable checkpointing for the framework.
-  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
-  frameworkInfo.set_checkpoint(true);
-
-  MesosSchedulerDriver driver(
-      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(_, _, _));
-
-  Filters filters;
-  filters.set_refuse_seconds(0);
-
-  // NOTE: We set filter explicitly here so that the resources will
-  // not be filtered for 5 seconds (by default).
-  Future<vector<Offer> > offers1;
-  EXPECT_CALL(sched, resourceOffers(_, _))
-    .WillOnce(FutureArg<1>(&offers1))
-    .WillRepeatedly(DeclineOffers(filters));      // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers1);
-  EXPECT_NE(0u, offers1.get().size());
-
-  Offer offer1 = offers1.get()[0];
-
-  // Start a long running task without using the network isolator.
-  TaskInfo task1 = createTask(
-      offer1.slave_id(),
-      Resources::parse("cpus:1;mem:512").get(),
-      "sleep 1000");
-
-  EXPECT_CALL(sched, statusUpdate(_, _));
-
-  Future<Nothing> _statusUpdateAcknowledgement1 =
-    FUTURE_DISPATCH(_, &Slave::_statusUpdateAcknowledgement);
-
-  driver.launchTasks(offers1.get()[0].id(), {task1}, filters);
-
-  // Wait for the ACK to be checkpointed.
-  AWAIT_READY(_statusUpdateAcknowledgement1);
-
-  Stop(slave.get());
-  delete containerizer1.get();
-
-  Future<Nothing> _recover1 = FUTURE_DISPATCH(_, &Slave::_recover);
-
-  Future<SlaveReregisteredMessage> slaveReregisteredMessage1 =
-    FUTURE_PROTOBUF(SlaveReregisteredMessage(), _, _);
-
-  Future<vector<Offer> > offers2;
-  EXPECT_CALL(sched, resourceOffers(_, _))
-    .WillOnce(FutureArg<1>(&offers2))
-    .WillRepeatedly(DeclineOffers(filters));      // Ignore subsequent offers.
-
-  // Restart the slave with the network isolator.
-  slaveFlags.isolation += ",network/port_mapping";
-
-  Try<MesosContainerizer*> containerizer2 =
-    MesosContainerizer::create(slaveFlags, true, &fetcher);
-
-  ASSERT_SOME(containerizer2);
-
-  slave = StartSlave(containerizer2.get(), slaveFlags);
-  ASSERT_SOME(slave);
-
-  Clock::pause();
-
-  AWAIT_READY(_recover1);
-
-  Clock::settle(); // Wait for slave to schedule reregister timeout.
-  Clock::advance(EXECUTOR_REREGISTER_TIMEOUT);
-
-  AWAIT_READY(slaveReregisteredMessage1);
-
-  Clock::settle(); // Make sure an allocation is scheduled.
-  Clock::advance(masterFlags.allocation_interval);
-
-  Clock::resume();
-
-  AWAIT_READY(offers2);
-  EXPECT_NE(0u, offers2.get().size());
-
-  Offer offer2 = offers2.get()[0];
-
-  // Start a long running task using the network isolator.
-  TaskInfo task2 = createTask(offer2, "sleep 1000");
-
-  EXPECT_CALL(sched, statusUpdate(_, _));
-
-  Future<Nothing> _statusUpdateAcknowledgement2 =
-    FUTURE_DISPATCH(_, &Slave::_statusUpdateAcknowledgement);
-
-  driver.launchTasks(offers2.get()[0].id(), {task2});
-
-  // Wait for the ACK to be checkpointed.
-  AWAIT_READY(_statusUpdateAcknowledgement2);
-
-  Stop(slave.get());
-  delete containerizer2.get();
-
-  Future<Nothing> _recover2 = FUTURE_DISPATCH(_, &Slave::_recover);
-
-  Future<SlaveReregisteredMessage> slaveReregisteredMessage2 =
-    FUTURE_PROTOBUF(SlaveReregisteredMessage(), _, _);
-
-  // Restart the slave with the network isolator. This is to verify
-  // the slave recovery case where one task is running with the
-  // network isolator and another task is running without it.
-  Try<MesosContainerizer*> containerizer3 =
-    MesosContainerizer::create(slaveFlags, true, &fetcher);
-
-  ASSERT_SOME(containerizer3);
-
-  slave = StartSlave(containerizer3.get(), slaveFlags);
-  ASSERT_SOME(slave);
-
-  Clock::pause();
-
-  AWAIT_READY(_recover2);
-
-  Clock::settle(); // Wait for slave to schedule reregister timeout.
-  Clock::advance(EXECUTOR_REREGISTER_TIMEOUT);
-
-  AWAIT_READY(slaveReregisteredMessage2);
-
-  Clock::resume();
-
-  // Ensure that both containers (with and without network isolation)
-  // were recovered.
-  Future<hashset<ContainerID>> containers = containerizer3.get()->containers();
-  AWAIT_READY(containers);
-  EXPECT_EQ(2u, containers.get().size());
-
-  foreach (const ContainerID& containerId, containers.get()) {
-    // Do some basic checks to make sure the network isolator can
-    // handle mixed types of containers correctly.
-    Future<ResourceStatistics> usage = 
containerizer3.get()->usage(containerId);
-    AWAIT_READY(usage);
-
-    // TODO(chzhcn): Write a more thorough test for update.
-  }
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-  delete containerizer3.get();
-}
-
-
-// Test that all configurations (tc filters etc) is cleaned up for an
-// orphaned container using the network isolator.
-TEST_F(PortMappingMesosTest, CGROUPS_ROOT_CleanUpOrphan)
-{
-  Try<PID<Master> > master = StartMaster();
-  ASSERT_SOME(master);
-
-  slave::Flags flags = CreateSlaveFlags();
-
-  // NOTE: We add 'cgroups/cpu,cgroups/mem' to bypass MESOS-2554.
-  flags.isolation = "cgroups/cpu,cgroups/mem,network/port_mapping";
-
-  Try<PID<Slave> > slave = StartSlave(flags);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-
-  // Enable checkpointing for the framework.
-  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
-  frameworkInfo.set_checkpoint(true);
-
-  MesosSchedulerDriver driver(
-      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
-
-  Future<FrameworkID> frameworkId;
-  EXPECT_CALL(sched, registered(_, _, _))
-    .WillOnce(FutureArg<1>(&frameworkId));
-
-  Future<vector<Offer> > offers;
-  EXPECT_CALL(sched, resourceOffers(_, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(DeclineOffers());      // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  // Start a long running task using network islator.
-  TaskInfo task = createTask(offers.get()[0], "sleep 1000");
-
-  EXPECT_CALL(sched, statusUpdate(_, _));
-
-  Future<Nothing> _statusUpdateAcknowledgement =
-    FUTURE_DISPATCH(_, &Slave::_statusUpdateAcknowledgement);
-
-  driver.launchTasks(offers.get()[0].id(), {task});
-
-  // Wait for the ACK to be checkpointed.
-  AWAIT_READY(_statusUpdateAcknowledgement);
-
-  Stop(slave.get());
-
-  // Wipe the slave meta directory so that the slave will treat the
-  // above running task as an orphan.
-  ASSERT_SOME(os::rmdir(paths::getMetaRootDir(flags.work_dir)));
-
-  Future<SlaveRegisteredMessage> slaveRegisteredMessage =
-    FUTURE_PROTOBUF(SlaveRegisteredMessage(), _, _);
-
-  Future<Nothing> orphansDestroyed =
-    FUTURE_DISPATCH(_, &MesosContainerizerProcess::___recover);
-
-  // Restart the slave.
-  slave = StartSlave(flags);
-  ASSERT_SOME(slave);
-
-  AWAIT_READY(slaveRegisteredMessage);
-
-  AWAIT_READY(orphansDestroyed);
-
-  // Expect that qdiscs still exist on eth0 and lo but with no filters.
-  Try<bool> hostEth0ExistsQdisc = ingress::exists(eth0);
-  EXPECT_SOME_TRUE(hostEth0ExistsQdisc);
-
-  Try<bool> hostLoExistsQdisc = ingress::exists(lo);
-  EXPECT_SOME_TRUE(hostLoExistsQdisc);
-
-  Result<vector<ip::Classifier> > classifiers =
-    ip::classifiers(eth0, ingress::HANDLE);
-
-  EXPECT_SOME(classifiers);
-  EXPECT_EQ(0u, classifiers.get().size());
-
-  classifiers = ip::classifiers(lo, ingress::HANDLE);
-  EXPECT_SOME(classifiers);
-  EXPECT_EQ(0u, classifiers.get().size());
-
-  // Expect no 'veth' devices.
-  Try<set<string> > links = net::links();
-  ASSERT_SOME(links);
-  foreach (const string& name, links.get()) {
-    EXPECT_FALSE(strings::startsWith(name, slave::PORT_MAPPING_VETH_PREFIX()));
-  }
-
-  // Expect no files in bind mount directory.
-  Try<list<string> > files = os::ls(slave::PORT_MAPPING_BIND_MOUNT_ROOT());
-  ASSERT_SOME(files);
-  EXPECT_EQ(0u, files.get().size());
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-
-// This test verfies the creation and destroy of the network namespace
-// handle symlink. The symlink was introduced in 0.23.0.
-TEST_F(PortMappingMesosTest, ROOT_NetworkNamespaceHandleSymlink)
-{
-  Try<PID<Master> > master = StartMaster();
-  ASSERT_SOME(master);
-
-  slave::Flags flags = CreateSlaveFlags();
-  flags.isolation = "network/port_mapping";
-
-  Try<MesosContainerizer*> containerizer =
-    MesosContainerizer::create(flags, true, &fetcher);
-
-  ASSERT_SOME(containerizer);
-
-  Try<PID<Slave>> slave = StartSlave(containerizer.get(), flags);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(_, _, _));
-
-  Future<vector<Offer> > offers;
-  EXPECT_CALL(sched, resourceOffers(_, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(DeclineOffers());      // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  // Start a long running task using network islator.
-  TaskInfo task = createTask(offers.get()[0], "sleep 1000");
-
-  Future<TaskStatus> status1;
-  Future<TaskStatus> status2;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status1))
-    .WillOnce(FutureArg<1>(&status2))
-    .WillRepeatedly(Return());       // Ignore subsequent updates.
-
-  driver.launchTasks(offers.get()[0].id(), {task});
-
-  AWAIT_READY(status1);
-  EXPECT_EQ(task.task_id(), status1.get().task_id());
-  EXPECT_EQ(TASK_RUNNING, status1.get().state());
-
-  Future<hashset<ContainerID>> containers = containerizer.get()->containers();
-  AWAIT_READY(containers);
-  ASSERT_EQ(1u, containers.get().size());
-
-  ContainerID containerId = *(containers.get().begin());
-
-  const string symlink = path::join(
-      slave::PORT_MAPPING_BIND_MOUNT_SYMLINK_ROOT(),
-      stringify(containerId));
-
-  EXPECT_TRUE(os::exists(symlink));
-  EXPECT_TRUE(os::stat::islink(symlink));
-
-  Future<containerizer::Termination> termination =
-    containerizer.get()->wait(containerId);
-
-  driver.killTask(task.task_id());
-
-  AWAIT_READY(status2);
-  EXPECT_EQ(task.task_id(), status2.get().task_id());
-  EXPECT_EQ(TASK_KILLED, status2.get().state());
-
-  AWAIT_READY(termination);
-  EXPECT_FALSE(os::exists(symlink));
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-
-  delete containerizer.get();
-}
-
-
-// This test verfies that the isolator is able to recover a mix of
-// known and unkonwn orphans. This is used to capture the regression
-// described in MESOS-2914.
-TEST_F(PortMappingMesosTest, CGROUPS_ROOT_RecoverMixedKnownAndUnKnownOrphans)
-{
-  Try<PID<Master>> master = StartMaster(CreateMasterFlags());
-  ASSERT_SOME(master);
-
-  slave::Flags flags = CreateSlaveFlags();
-  flags.isolation = "network/port_mapping";
-
-  Try<MesosContainerizer*> containerizer =
-    MesosContainerizer::create(flags, true, &fetcher);
-
-  ASSERT_SOME(containerizer);
-
-  Try<PID<Slave> > slave = StartSlave(containerizer.get(), flags);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-
-  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
-  frameworkInfo.set_checkpoint(true);
-
-  MesosSchedulerDriver driver(
-      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
-
-  EXPECT_CALL(sched, registered(_, _, _));
-
-  Future<vector<Offer> > offers;
-  EXPECT_CALL(sched, resourceOffers(_, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(DeclineOffers());      // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(offers);
-  EXPECT_NE(0u, offers.get().size());
-
-  Offer offer = offers.get()[0];
-
-  TaskInfo task1 = createTask(
-      offer.slave_id(),
-      Resources::parse("cpus:1;mem:64").get(),
-      "sleep 1000");
-
-  TaskInfo task2 = createTask(
-      offer.slave_id(),
-      Resources::parse("cpus:1;mem:64").get(),
-      "sleep 1000");
-
-  Future<TaskStatus> status1;
-  Future<TaskStatus> status2;
-  EXPECT_CALL(sched, statusUpdate(&driver, _))
-    .WillOnce(FutureArg<1>(&status1))
-    .WillOnce(FutureArg<1>(&status2))
-    .WillRepeatedly(Return());       // Ignore subsequent updates.
-
-  driver.launchTasks(offers.get()[0].id(), {task1, task2});
-
-  AWAIT_READY(status1);
-  ASSERT_EQ(TASK_RUNNING, status1.get().state());
-
-  AWAIT_READY(status2);
-  ASSERT_EQ(TASK_RUNNING, status2.get().state());
-
-  // Obtain the container IDs.
-  Future<hashset<ContainerID>> containers = containerizer.get()->containers();
-  AWAIT_READY(containers);
-  ASSERT_EQ(2u, containers.get().size());
-
-  Stop(slave.get());
-  delete containerizer.get();
-
-  // Wipe the slave meta directory so that the slave will treat the
-  // above running tasks as orphans.
-  ASSERT_SOME(os::rmdir(paths::getMetaRootDir(flags.work_dir)));
-
-  // Remove the network namespace symlink for one container so that it
-  // becomes an unknown orphan.
-  const ContainerID containerId = *(containers.get().begin());
-  const string symlink = path::join(
-      slave::PORT_MAPPING_BIND_MOUNT_SYMLINK_ROOT(),
-      stringify(containerId));
-
-  ASSERT_TRUE(os::exists(symlink));
-  ASSERT_TRUE(os::stat::islink(symlink));
-  ASSERT_SOME(os::rm(symlink));
-
-  Future<SlaveRegisteredMessage> slaveRegisteredMessage =
-    FUTURE_PROTOBUF(SlaveRegisteredMessage(), _, _);
-
-  Future<Nothing> knownOrphansDestroyed =
-    FUTURE_DISPATCH(_, &MesosContainerizerProcess::___recover);
-
-  // Restart the slave.
-  slave = StartSlave(flags);
-  ASSERT_SOME(slave);
-
-  AWAIT_READY(slaveRegisteredMessage);
-  AWAIT_READY(knownOrphansDestroyed);
-
-  // We settle the clock here to ensure that the processing of
-  // 'MesosContainerizerProcess::___destroy()' is complete and the
-  // metric is updated.
-  Clock::pause();
-  Clock::settle();
-  Clock::resume();
-
-  JSON::Object metrics = Metrics();
-  EXPECT_EQ(
-      0u,
-      metrics.values["containerizer/mesos/container_destroy_errors"]);
-}
-
-} // namespace tests {
-} // namespace internal {
-} // namespace mesos {

Reply via email to