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/05/29 19:41:01 UTC

[23/35] Renamed 'third_party' to '3rdparty'.

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/statistics.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/statistics.cpp b/3rdparty/libprocess/src/statistics.cpp
new file mode 100644
index 0000000..d8f5ad1
--- /dev/null
+++ b/3rdparty/libprocess/src/statistics.cpp
@@ -0,0 +1,508 @@
+#include <glog/logging.h>
+
+#include <algorithm>
+#include <list>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <process/clock.hpp>
+#include <process/delay.hpp>
+#include <process/dispatch.hpp>
+#include <process/future.hpp>
+#include <process/http.hpp>
+#include <process/process.hpp>
+#include <process/statistics.hpp>
+#include <process/time.hpp>
+
+#include <stout/error.hpp>
+#include <stout/duration.hpp>
+#include <stout/foreach.hpp>
+#include <stout/hashmap.hpp>
+#include <stout/hashset.hpp>
+#include <stout/json.hpp>
+#include <stout/none.hpp>
+#include <stout/numify.hpp>
+#include <stout/option.hpp>
+#include <stout/stringify.hpp>
+#include <stout/strings.hpp>
+
+using namespace process;
+using namespace process::http;
+
+using std::list;
+using std::map;
+using std::string;
+using std::vector;
+
+namespace process {
+
+// This is initialized by process::initialize().
+Statistics* statistics = NULL;
+
+// TODO(bmahler): Move time series related logic into this struct.
+// TODO(bmahler): Investigate using google's btree implementation.
+// This provides better insertion and lookup performance for large
+// containers. This _should_ also provide significant memory
+// savings, especially since:
+//   1. Our insertion order will mostly be in sorted order.
+//   2. Our keys (Seconds) have efficient comparison operators.
+// See: http://code.google.com/p/cpp-btree/
+//      http://code.google.com/p/cpp-btree/wiki/UsageInstructions
+struct TimeSeries
+{
+  TimeSeries() : values(), archived(false) {}
+
+  // We use a map instead of a hashmap to store the values because
+  // that way we can retrieve a series in sorted order efficiently.
+  map<Time, double> values;
+  bool archived;
+};
+
+
+class StatisticsProcess : public Process<StatisticsProcess>
+{
+public:
+  StatisticsProcess(const Duration& _window)
+    : ProcessBase("statistics"),
+      window(_window) {}
+
+  virtual ~StatisticsProcess() {}
+
+  // Statistics implementation.
+  map<Time, double> timeseries(
+      const string& context,
+      const string& name,
+      const Option<Time>& start,
+      const Option<Time>& stop);
+
+  Option<double> get(const string& context, const string& name);
+
+  map<string, double> get(const string& context);
+
+  Try<Nothing> meter(
+      const string& context,
+      const string& name,
+      const Owned<meters::Meter>& meter);
+
+  void set(
+      const string& context,
+      const string& name,
+      double value,
+      const Time& time);
+
+  void archive(const string& context, const string& name);
+
+  void increment(const string& context, const string& name);
+
+  void decrement(const string& context, const string& name);
+
+protected:
+  virtual void initialize()
+  {
+    route("/snapshot.json", &StatisticsProcess::snapshot);
+    route("/series.json", &StatisticsProcess::series);
+
+    // Schedule the first truncation.
+    delay(STATISTICS_TRUNCATION_INTERVAL, self(), &StatisticsProcess::truncate);
+  }
+
+private:
+  // Removes values for the specified statistic that occurred outside
+  // the time series window.
+  // NOTE: We always ensure there is at least 1 value left for a statistic,
+  // unless it is archived!
+  // Returns true iff the time series is empty.
+  bool truncate(const string& context, const string& name);
+
+  // Removes values for all statistics that occurred outside the time
+  // series window.
+  // NOTE: Runs periodically every STATISTICS_TRUNCATION_INTERVAL.
+  // NOTE: We always ensure there is at least 1 value left for a statistic,
+  // unless it is archived.
+  void truncate();
+
+  // Returns the a snapshot of all statistics in JSON.
+  Future<Response> snapshot(const Request& request);
+
+  // Returns the time series of a statistic in JSON.
+  Future<Response> series(const Request& request);
+
+  const Duration window;
+
+  // This maps from {context: {name: TimeSeries } }.
+  hashmap<string, hashmap<string, TimeSeries> > statistics;
+
+  // Each statistic can have many meters.
+  // This maps from {context: {name: [meters] } }.
+  hashmap<string, hashmap<string, list<Owned<meters::Meter> > > > meters;
+};
+
+
+Try<Nothing> StatisticsProcess::meter(
+    const string& context,
+    const string& name,
+    const Owned<meters::Meter>& meter)
+{
+  if (meter->name == name) {
+    return Error("Meter name must not match the statistic name");
+  }
+
+  // Check for a duplicate meter.
+  foreachkey (const string& context, meters) {
+    foreachkey (const string& name, meters[context]) {
+      foreach (Owned<meters::Meter>& existing, meters[context][name]) {
+        if (meter->name == existing->name) {
+          return Error("Meter name matched existing meter name");
+        }
+      }
+    }
+  }
+
+  // Add the meter.
+  meters[context][name].push_back(meter);
+
+  return Nothing();
+}
+
+
+map<Time, double> StatisticsProcess::timeseries(
+    const string& context,
+    const string& name,
+    const Option<Time>& start,
+    const Option<Time>& stop)
+{
+  if (!statistics.contains(context) || !statistics[context].contains(name)) {
+    return map<Time, double>();
+  }
+
+  const std::map<Time, double>& values =
+    statistics[context].find(name)->second.values;
+
+  map<Time, double>::const_iterator lower = values.lower_bound(start.isSome()
+      ? start.get() : Time::EPOCH);
+
+  map<Time, double>::const_iterator upper = values.upper_bound(stop.isSome()
+      ? stop.get() : Time::MAX);
+
+  return map<Time, double>(lower, upper);
+}
+
+
+Option<double> StatisticsProcess::get(const string& context, const string& name)
+{
+  if (!statistics.contains(context) ||
+      !statistics[context].contains(name) ||
+      statistics[context][name].values.empty()) {
+    return Option<double>::none();
+  } else {
+    return statistics[context][name].values.rbegin()->second;
+  }
+}
+
+
+map<string, double> StatisticsProcess::get(const string& context)
+{
+  map<string, double> results;
+
+  if (!statistics.contains(context)) {
+    return results;
+  }
+
+  foreachkey (const string& name, statistics[context]) {
+    const map<Time, double>& values = statistics[context][name].values;
+
+    if (!values.empty()) {
+      results[name] = values.rbegin()->second;
+    }
+  }
+
+  return results;
+}
+
+
+void StatisticsProcess::set(
+    const string& context,
+    const string& name,
+    double value,
+    const Time& time)
+{
+  statistics[context][name].values[time] = value; // Update the raw value.
+  statistics[context][name].archived = false;     // Unarchive.
+
+  truncate(context, name);
+
+  // Update the metered values, if necessary.
+  if (meters.contains(context) && meters[context].contains(name)) {
+    foreach (Owned<meters::Meter>& meter, meters[context][name]) {
+      const Option<double>& update = meter->update(time, value);
+      statistics[context][meter->name].archived = false; // Unarchive.
+
+      if (update.isSome()) {
+        statistics[context][meter->name].values[time] = update.get();
+        truncate(context, meter->name);
+      }
+    }
+  }
+}
+
+
+void StatisticsProcess::archive(const string& context, const string& name)
+{
+  // Exclude the statistic from the snapshot.
+  statistics[context][name].archived = true;
+
+  // Remove any meters as well.
+  if (meters.contains(context) && meters[context].contains(name)) {
+    foreach (const Owned<meters::Meter>& meter, meters[context][name]) {
+      statistics[context][meter->name].archived = true;
+    }
+    meters[context].erase(name);
+  }
+}
+
+
+void StatisticsProcess::increment(const string& context, const string& name)
+{
+  double value = 0.0;
+  if (!statistics[context][name].values.empty()) {
+    value = statistics[context][name].values.rbegin()->second;
+  }
+  set(context, name, value + 1.0, Clock::now());
+}
+
+
+void StatisticsProcess::decrement(const string& context, const string& name)
+{
+  double value = 0.0;
+  if (!statistics[context][name].values.empty()) {
+    value = statistics[context][name].values.rbegin()->second;
+  }
+  set(context, name, value - 1.0, Clock::now());
+}
+
+
+bool StatisticsProcess::truncate(const string& context, const string& name)
+{
+  CHECK(statistics.contains(context));
+  CHECK(statistics[context].contains(name));
+
+  if (statistics[context][name].values.empty()) {
+    return true; // No truncation is needed, the time series is already empty.
+  }
+
+  map<Time, double>::iterator start =
+    statistics[context][name].values.begin();
+
+  while ((Clock::now() - start->first) > window) {
+    // Always keep at least one value for a statistic, unless it's archived!
+    if (statistics[context][name].values.size() == 1) {
+      if (statistics[context][name].archived) {
+        statistics[context][name].values.clear();
+      }
+      break;
+    }
+
+    statistics[context][name].values.erase(start);
+    start = statistics[context][name].values.begin();
+  }
+
+  return statistics[context][name].values.empty();
+}
+
+
+void StatisticsProcess::truncate()
+{
+  hashmap<string, hashset<string> > empties;
+
+  foreachkey (const string& context, statistics) {
+    foreachkey (const string& name, statistics[context]) {
+      // Keep track of the emptied timeseries.
+      if (truncate(context, name)) {
+        empties[context].insert(name);
+      }
+    }
+  }
+
+  // Remove the empty timeseries.
+  foreachkey (const string& context, empties) {
+    foreach (const string& name, empties[context]) {
+      statistics[context].erase(name);
+    }
+  }
+
+  delay(STATISTICS_TRUNCATION_INTERVAL, self(), &StatisticsProcess::truncate);
+}
+
+
+Future<Response> StatisticsProcess::snapshot(const Request& request)
+{
+  JSON::Array array;
+
+  Option<string> queryContext = request.query.get("context");
+  Option<string> queryName = request.query.get("name");
+
+  foreachkey (const string& context, statistics) {
+    foreachkey (const string& name, statistics[context]) {
+      // Exclude archived and empty time series.
+      if (statistics[context][name].archived ||
+          statistics[context][name].values.empty()) {
+        continue;
+      }
+
+      // Skip statistics that don't match the query, if present.
+      if (queryContext.isSome() && queryContext.get() != context) {
+        continue;
+      } else if (queryName.isSome() && queryName.get() != name) {
+        continue;
+      }
+
+      JSON::Object object;
+      object.values["context"] = context;
+      object.values["name"] = name;
+      object.values["time"] =
+        statistics[context][name].values.rbegin()->first.secs();
+      object.values["value"] =
+        statistics[context][name].values.rbegin()->second;
+      array.values.push_back(object);
+    }
+  }
+
+  return OK(array, request.query.get("jsonp"));
+}
+
+
+Future<Response> StatisticsProcess::series(const Request& request)
+{
+  Option<string> context = request.query.get("context");
+  Option<string> name = request.query.get("name");
+
+  if (!context.isSome()) {
+    return BadRequest("Expected 'context=val' in query.\n");
+  } else if (!name.isSome()) {
+    return BadRequest("Expected 'name=val' in query.\n");
+  }
+
+  Option<Time> start = None();
+  Option<Time> stop = None();
+
+  if (request.query.get("start").isSome()) {
+    Try<double> result = numify<double>(request.query.get("start").get());
+    if (result.isError()) {
+      return BadRequest("Failed to parse 'start': " + result.error());
+    }
+
+    Try<Time> start_ = Time::create(result.get());
+    if (start_.isError()) {
+      return BadRequest("Failed to parse 'start': " + start_.error());
+    }
+    start = start_.get();
+  }
+
+  if (request.query.get("stop").isSome()) {
+    Try<double> result = numify<double>(request.query.get("stop").get());
+    if (result.isError()) {
+      return BadRequest("Failed to parse 'stop': " + result.error());
+    }
+
+    Try<Time> stop_ = Time::create(result.get());
+    if (stop_.isError()) {
+      return BadRequest("Failed to parse 'stop': " + stop_.error());
+    }
+    stop = stop_.get();
+  }
+
+  JSON::Array array;
+
+  const map<Time, double>& values =
+    timeseries(context.get(), name.get(), start, stop);
+
+  foreachpair (const Time& s, double value, values) {
+    JSON::Object object;
+    object.values["time"] = s.secs();
+    object.values["value"] = value;
+    array.values.push_back(object);
+  }
+
+  return OK(array, request.query.get("jsonp"));
+}
+
+
+Statistics::Statistics(const Duration& window)
+{
+  process = new StatisticsProcess(window);
+  spawn(process);
+}
+
+
+Statistics::~Statistics()
+{
+  terminate(process);
+  wait(process);
+}
+
+
+Future<map<Time, double> > Statistics::timeseries(
+    const string& context,
+    const string& name,
+    const Option<Time>& start,
+    const Option<Time>& stop)
+{
+  return dispatch(
+      process, &StatisticsProcess::timeseries, context, name, start, stop);
+}
+
+
+Future<Option<double> > Statistics::get(
+    const string& context,
+    const string& name)
+{
+  return dispatch(process, &StatisticsProcess::get, context, name);
+}
+
+
+Future<map<string, double> > Statistics::get(const string& context)
+{
+  return dispatch(process, &StatisticsProcess::get, context);
+}
+
+
+Future<Try<Nothing> > Statistics::meter(
+    const string& context,
+    const string& name,
+    Owned<meters::Meter> meter)
+{
+
+  return dispatch(process, &StatisticsProcess::meter, context, name, meter);
+}
+
+
+void Statistics::set(
+    const string& context,
+    const string& name,
+    double value,
+    const Time& time)
+{
+  dispatch(process, &StatisticsProcess::set, context, name, value, time);
+}
+
+
+void Statistics::archive(const string& context, const string& name)
+{
+  dispatch(process, &StatisticsProcess::archive, context, name);
+}
+
+
+void Statistics::increment(const string& context, const string& name)
+{
+  dispatch(process, &StatisticsProcess::increment, context, name);
+}
+
+
+void Statistics::decrement(const string& context, const string& name)
+{
+  dispatch(process, &StatisticsProcess::decrement, context, name);
+}
+
+} // namespace process {

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/synchronized.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/synchronized.cpp b/3rdparty/libprocess/src/synchronized.cpp
new file mode 100644
index 0000000..79b0849
--- /dev/null
+++ b/3rdparty/libprocess/src/synchronized.cpp
@@ -0,0 +1,66 @@
+#include "synchronized.hpp"
+
+using std::string;
+
+
+static string s1;
+static synchronizable(s1);
+
+static string s2;
+static synchronizable(s2) = SYNCHRONIZED_INITIALIZER;
+
+static string s3;
+static synchronizable(s3) = SYNCHRONIZED_INITIALIZER_RECURSIVE;
+
+
+void bar()
+{
+  synchronized(s3) {
+
+  }
+}
+
+
+void foo()
+{
+  synchronized(s3) {
+    bar();
+  }
+}
+
+
+class Foo
+{
+public:
+  Foo()
+  {
+    synchronizer(s) = SYNCHRONIZED_INITIALIZER_RECURSIVE;
+  }
+
+  void foo()
+  {
+    synchronized(s) {
+      synchronized(s) {
+
+      }
+    }
+  }
+  
+private:
+  string s;
+  synchronizable(s);
+};
+
+
+int main(int argc, char **argv)
+{
+  synchronizer(s1) = SYNCHRONIZED_INITIALIZER_RECURSIVE;
+  //synchronizer(s2) = SYNCHRONIZED_INITIALIZER;
+
+  //foo();
+
+  Foo f;
+  f.foo();
+
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/synchronized.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/synchronized.hpp b/3rdparty/libprocess/src/synchronized.hpp
new file mode 100644
index 0000000..7e0efe2
--- /dev/null
+++ b/3rdparty/libprocess/src/synchronized.hpp
@@ -0,0 +1,104 @@
+#include <pthread.h>
+
+#include <iostream>
+
+
+class Synchronizable
+{
+public:
+  Synchronizable()
+    : initialized(false) {}
+
+  explicit Synchronizable(int _type)
+    : type(_type), initialized(false)
+  {
+    initialize();
+  }
+
+  Synchronizable(const Synchronizable &that)
+  {
+    type = that.type;
+    initialize();
+  }
+
+  Synchronizable & operator = (const Synchronizable &that)
+  {
+    type = that.type;
+    initialize();
+    return *this;
+  }
+
+  void acquire()
+  {
+    if (!initialized) {
+      std::cerr << "synchronizable not initialized" << std::endl;
+      abort();
+    }
+    pthread_mutex_lock(&mutex);
+  }
+
+  void release()
+  {
+    if (!initialized) {
+      std::cerr << "synchronizable not initialized" << std::endl;
+      abort();
+    }
+    pthread_mutex_unlock(&mutex);
+  }
+
+private:
+  void initialize()
+  {
+    if (!initialized) {
+      pthread_mutexattr_t attr;
+      pthread_mutexattr_init(&attr);
+      pthread_mutexattr_settype(&attr, type);
+      pthread_mutex_init(&mutex, &attr);
+      pthread_mutexattr_destroy(&attr);
+      initialized = true;
+    } else {
+      std::cerr << "synchronizable already initialized" << std::endl;
+      abort();
+    }
+  }
+
+  int type;
+  bool initialized;
+  pthread_mutex_t mutex;
+};
+
+
+class Synchronized
+{
+public:
+  Synchronized(Synchronizable *_synchronizable)
+    : synchronizable(_synchronizable)
+  {
+    synchronizable->acquire();
+  }
+
+  ~Synchronized()
+  {
+    synchronizable->release();
+  }
+
+  operator bool () { return true; }
+
+private:
+  Synchronizable *synchronizable;
+};
+
+
+#define synchronized(s)                                                 \
+  if (Synchronized __synchronized ## s = Synchronized(&__synchronizable_ ## s))
+
+#define synchronizable(s)                       \
+  Synchronizable __synchronizable_ ## s
+
+#define synchronizer(s)                         \
+  (__synchronizable_ ## s)
+
+
+#define SYNCHRONIZED_INITIALIZER Synchronizable(PTHREAD_MUTEX_NORMAL)
+#define SYNCHRONIZED_INITIALIZER_DEBUG Synchronizable(PTHREAD_MUTEX_ERRORCHECK)
+#define SYNCHRONIZED_INITIALIZER_RECURSIVE Synchronizable(PTHREAD_MUTEX_RECURSIVE)

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/test-master.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/test-master.cpp b/3rdparty/libprocess/src/test-master.cpp
new file mode 100644
index 0000000..23c6e1d
--- /dev/null
+++ b/3rdparty/libprocess/src/test-master.cpp
@@ -0,0 +1,62 @@
+#include <io.hpp>
+#include <tuple.hpp>
+
+#include <string>
+
+#include "test.hpp"
+
+using std::string;
+
+
+using namespace process::tuple;
+
+
+class Master : public Tuple<Process>
+{
+private:
+  int id;
+
+protected:
+  void operator () ()
+  {
+    do {
+      switch (receive()) {
+      case REGISTER: {
+	Out::println("Master received REGISTER");
+
+	string name;
+	unpack<REGISTER>(name);
+
+	Out::println("Registered slave: %s", name.c_str());
+
+	send(from(), pack<OKAY>(id++));
+	break;
+      }
+      case UNREGISTER: {
+	Out::println("Master received UNREGISTER");
+
+	int slave_id;
+	unpack<UNREGISTER>(slave_id);
+
+	Out::println("Unregistered slave id: %d", slave_id);
+
+	send(from(), pack<OKAY>(0));
+	break;
+      }
+      default:
+	Out::println("UNKNOWN MESSAGE RECEIVED");
+      }
+    } while (true);
+  }
+
+public:
+  Master() : id(0) {}
+};
+
+
+int main(int argc, char **argv)
+{
+  PID master = Process::spawn(new Master());
+  Out::println("master: %s", string(master).c_str());
+  Process::wait(master);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/test-slave.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/test-slave.cpp b/3rdparty/libprocess/src/test-slave.cpp
new file mode 100644
index 0000000..fe08ce8
--- /dev/null
+++ b/3rdparty/libprocess/src/test-slave.cpp
@@ -0,0 +1,61 @@
+#include <test.hpp>
+
+using namespace process::record;
+
+class Slave : public RecordProcess
+{
+private:
+  PID master;
+  int id;
+
+protected:
+  void operator () ()
+  {
+    send(master, pack<REGISTER>("c3po"));
+
+    switch (receive()) {
+    case OKAY: {
+      std::cout << "slave registered" << std::endl;
+      unpack<OKAY>(id);
+      std::cout << "slave id: " << id << std::endl;
+      break;
+    }
+    default:
+      std::cout << "slave failed to register" << std::endl;
+      break;
+    }
+
+    send(master, pack<UNREGISTER>(id));
+
+    switch (receive()) {
+    case OKAY:
+      std::cout << "slave unregistered" << std::endl;
+      break;
+    default:
+      std::cout << "slave failed to unregister" << std::endl;
+      break;
+    }
+
+    link(master);
+    switch (receive()) {
+    case PROCESS_EXIT:
+      std::cout << "master exited" << std::endl;
+      break;
+    default:
+      std::cout << "unexpected message" << std::endl;
+      break;
+    }
+  }
+
+public:
+  Slave(const PID &_master) : master(_master) {}
+};
+
+
+int main(int argc, char **argv)
+{
+  PID master = make_pid(argv[1]);
+  PID slave = Process::spawn(new Slave(master));
+  std::cout << "slave is at " << slave << std::endl;
+  Process::wait(slave);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/tests/decoder_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/decoder_tests.cpp b/3rdparty/libprocess/src/tests/decoder_tests.cpp
new file mode 100644
index 0000000..04ca3ff
--- /dev/null
+++ b/3rdparty/libprocess/src/tests/decoder_tests.cpp
@@ -0,0 +1,128 @@
+#include <gmock/gmock.h>
+
+#include <deque>
+#include <string>
+
+#include <process/socket.hpp>
+
+#include <stout/gtest.hpp>
+
+#include "decoder.hpp"
+
+using namespace process;
+using namespace process::http;
+
+using std::deque;
+using std::string;
+
+
+TEST(Decoder, Request)
+{
+  DataDecoder decoder = DataDecoder(Socket());
+
+  const string& data =
+    "GET /path/file.json?key1=value1&key2=value2#fragment HTTP/1.1\r\n"
+    "Host: localhost\r\n"
+    "Connection: close\r\n"
+    "Accept-Encoding: compress, gzip\r\n"
+    "\r\n";
+
+  deque<Request*> requests = decoder.decode(data.data(), data.length());
+  ASSERT_FALSE(decoder.failed());
+  ASSERT_EQ(1, requests.size());
+
+  Request* request = requests[0];
+  EXPECT_EQ("GET", request->method);
+  EXPECT_EQ("/path/file.json", request->path);
+  EXPECT_EQ("/path/file.json?key1=value1&key2=value2#fragment", request->url);
+  EXPECT_EQ("fragment", request->fragment);
+  EXPECT_TRUE(request->body.empty());
+  EXPECT_FALSE(request->keepAlive);
+
+  EXPECT_EQ(3, request->headers.size());
+  EXPECT_SOME_EQ("localhost", request->headers.get("Host"));
+  EXPECT_SOME_EQ("close", request->headers.get("Connection"));
+  EXPECT_SOME_EQ("compress, gzip", request->headers.get("Accept-Encoding"));
+
+  EXPECT_EQ(2, request->query.size());
+  EXPECT_SOME_EQ("value1", request->query.get("key1"));
+  EXPECT_SOME_EQ("value2", request->query.get("key2"));
+
+  delete request;
+}
+
+
+TEST(Decoder, RequestHeaderContinuation)
+{
+  DataDecoder decoder = DataDecoder(Socket());
+
+  const string& data =
+    "GET /path/file.json HTTP/1.1\r\n"
+    "Host: localhost\r\n"
+    "Connection: close\r\n"
+    "Accept-Encoding: compress,"
+    "                 gzip\r\n"
+    "\r\n";
+
+  deque<Request*> requests = decoder.decode(data.data(), data.length());
+  ASSERT_FALSE(decoder.failed());
+  ASSERT_EQ(1, requests.size());
+
+  Request* request = requests[0];
+  EXPECT_SOME_EQ("compress,                 gzip",
+                 request->headers.get("Accept-Encoding"));
+  delete request;
+}
+
+
+// This is expected to fail for now, see my TODO(bmahler) on http::Request.
+TEST(Decoder, DISABLED_RequestHeaderCaseInsensitive)
+{
+  DataDecoder decoder = DataDecoder(Socket());
+
+  const string& data =
+    "GET /path/file.json HTTP/1.1\r\n"
+    "Host: localhost\r\n"
+    "cOnnECtioN: close\r\n"
+    "accept-ENCODING: compress, gzip\r\n"
+    "\r\n";
+
+  deque<Request*> requests = decoder.decode(data.data(), data.length());
+  ASSERT_FALSE(decoder.failed());
+  ASSERT_EQ(1, requests.size());
+
+  Request* request = requests[0];
+  EXPECT_FALSE(request->keepAlive);
+
+  EXPECT_SOME_EQ("compress, gzip", request->headers.get("Accept-Encoding"));
+
+  delete request;
+}
+
+
+TEST(Decoder, Response)
+{
+  ResponseDecoder decoder;
+
+  const string& data =
+    "HTTP/1.1 200 OK\r\n"
+    "Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n"
+    "Content-Type: text/plain\r\n"
+    "Content-Length: 2\r\n"
+    "\r\n"
+    "hi";
+
+  deque<Response*> requests = decoder.decode(data.data(), data.length());
+  ASSERT_FALSE(decoder.failed());
+  ASSERT_EQ(1, requests.size());
+
+  Response* response = requests[0];
+
+  EXPECT_EQ("200 OK", response->status);
+  EXPECT_EQ(Response::BODY, response->type);
+  EXPECT_EQ("hi", response->body);
+
+  EXPECT_EQ(3, response->headers.size());
+
+  delete response;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/tests/encoder_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/encoder_tests.cpp b/3rdparty/libprocess/src/tests/encoder_tests.cpp
new file mode 100644
index 0000000..fccb865
--- /dev/null
+++ b/3rdparty/libprocess/src/tests/encoder_tests.cpp
@@ -0,0 +1,92 @@
+#include <gmock/gmock.h>
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include <process/http.hpp>
+#include <process/socket.hpp>
+
+#include <stout/gtest.hpp>
+
+#include "encoder.hpp"
+#include "decoder.hpp"
+
+using namespace process;
+using namespace process::http;
+
+using std::deque;
+using std::string;
+using std::vector;
+
+
+TEST(Encoder, Response)
+{
+  Request request;
+  const OK& response("body");
+
+  // Encode the response.
+  const string& encoded = HttpResponseEncoder::encode(response, request);
+
+  // Now decode it back, and verify the encoding was correct.
+  ResponseDecoder decoder;
+  deque<Response*> responses = decoder.decode(encoded.data(), encoded.length());
+  ASSERT_FALSE(decoder.failed());
+  ASSERT_EQ(1, responses.size());
+
+  Response* decoded = responses[0];
+  EXPECT_EQ("200 OK", decoded->status);
+  EXPECT_EQ("body", decoded->body);
+
+  // Encoding should have inserted the 'Date' and 'Content-Length' headers.
+  EXPECT_EQ(2, decoded->headers.size());
+  EXPECT_TRUE(decoded->headers.contains("Date"));
+  EXPECT_SOME_EQ(
+      stringify(response.body.size()),
+      decoded->headers.get("Content-Length"));
+}
+
+
+TEST(Encoder, AcceptableEncodings)
+{
+  // Create requests that do not accept gzip encoding.
+  vector<Request> requests(7);
+  requests[0].headers["Accept-Encoding"] = "gzip;q=0.0,*";
+  requests[1].headers["Accept-Encoding"] = "compress";
+  requests[2].headers["Accept-Encoding"] = "compress, gzip;q=0.0";
+  requests[3].headers["Accept-Encoding"] = "*, gzip;q=0.0";
+  requests[4].headers["Accept-Encoding"] = "*;q=0.0, compress";
+  requests[5].headers["Accept-Encoding"] = "\n compress";
+  requests[6].headers["Accept-Encoding"] = "compress,\tgzip;q=0.0";
+
+  foreach (const Request& request, requests) {
+    EXPECT_FALSE(request.accepts("gzip"))
+      << "Gzip encoding is unacceptable for 'Accept-Encoding: "
+      << request.headers.get("Accept-Encoding").get() << "'";
+  }
+
+  // Create requests that accept gzip encoding.
+  vector<Request> gzipRequests(12);
+
+  // Using q values.
+  gzipRequests[0].headers["Accept-Encoding"] = "gzip;q=0.1,*";
+  gzipRequests[1].headers["Accept-Encoding"] = "compress, gzip;q=0.1";
+  gzipRequests[2].headers["Accept-Encoding"] = "*, gzip;q=0.5";
+  gzipRequests[3].headers["Accept-Encoding"] = "*;q=0.9, compress";
+  gzipRequests[4].headers["Accept-Encoding"] = "compress,\tgzip;q=0.1";
+
+  // No q values.
+  gzipRequests[5].headers["Accept-Encoding"] = "gzip";
+  gzipRequests[6].headers["Accept-Encoding"] = "compress, gzip";
+  gzipRequests[7].headers["Accept-Encoding"] = "*";
+  gzipRequests[8].headers["Accept-Encoding"] = "*, compress";
+  gzipRequests[9].headers["Accept-Encoding"] = "\n gzip";
+  gzipRequests[10].headers["Accept-Encoding"] = "compress,\tgzip";
+  gzipRequests[11].headers["Accept-Encoding"] = "gzip";
+
+  foreach (const Request& gzipRequest, gzipRequests) {
+    EXPECT_TRUE(gzipRequest.accepts("gzip"))
+      << "Gzip encoding is acceptable for 'Accept-Encoding: "
+      << gzipRequest.headers.get("Accept-Encoding").get() << "'";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/tests/http_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/http_tests.cpp b/3rdparty/libprocess/src/tests/http_tests.cpp
new file mode 100644
index 0000000..f677267
--- /dev/null
+++ b/3rdparty/libprocess/src/tests/http_tests.cpp
@@ -0,0 +1,133 @@
+#include <arpa/inet.h>
+
+#include <gmock/gmock.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <string>
+
+#include <process/future.hpp>
+#include <process/gmock.hpp>
+#include <process/gtest.hpp>
+#include <process/http.hpp>
+#include <process/io.hpp>
+
+#include <stout/gtest.hpp>
+#include <stout/nothing.hpp>
+#include <stout/os.hpp>
+
+#include "encoder.hpp"
+
+using namespace process;
+
+using testing::_;
+using testing::Assign;
+using testing::DoAll;
+using testing::Return;
+
+
+class HttpProcess : public Process<HttpProcess>
+{
+public:
+  HttpProcess()
+  {
+    route("/body", &HttpProcess::body);
+    route("/pipe", &HttpProcess::pipe);
+  }
+
+  MOCK_METHOD1(body, Future<http::Response>(const http::Request&));
+  MOCK_METHOD1(pipe, Future<http::Response>(const http::Request&));
+};
+
+
+TEST(HTTP, Endpoints)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  HttpProcess process;
+
+  spawn(process);
+
+  // First hit '/body' (using explicit sockets and HTTP/1.0).
+  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+
+  ASSERT_LE(0, s);
+
+  sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = PF_INET;
+  addr.sin_port = htons(process.self().port);
+  addr.sin_addr.s_addr = process.self().ip;
+
+  ASSERT_EQ(0, connect(s, (sockaddr*) &addr, sizeof(addr)));
+
+  std::ostringstream out;
+  out << "GET /" << process.self().id << "/body"
+      << " HTTP/1.0\r\n"
+      << "Connection: Keep-Alive\r\n"
+      << "\r\n";
+
+  const std::string& data = out.str();
+
+  EXPECT_CALL(process, body(_))
+    .WillOnce(Return(http::OK()));
+
+   ASSERT_SOME(os::write(s, data));
+
+  std::string response = "HTTP/1.1 200 OK";
+
+  char temp[response.size()];
+  ASSERT_LT(0, ::read(s, temp, response.size()));
+  ASSERT_EQ(response, std::string(temp, response.size()));
+
+  ASSERT_EQ(0, close(s));
+
+  // Now hit '/pipe' (by using http::get).
+  int pipes[2];
+  ASSERT_NE(-1, ::pipe(pipes));
+
+  http::OK ok;
+  ok.type = http::Response::PIPE;
+  ok.pipe = pipes[0];
+
+  Future<Nothing> pipe;
+  EXPECT_CALL(process, pipe(_))
+    .WillOnce(DoAll(FutureSatisfy(&pipe),
+                    Return(ok)));
+
+  Future<http::Response> future = http::get(process.self(), "pipe");
+
+  AWAIT_READY(pipe);
+
+  ASSERT_SOME(os::write(pipes[1], "Hello World\n"));
+  ASSERT_SOME(os::close(pipes[1]));
+
+  AWAIT_READY(future);
+  ASSERT_EQ(http::statuses[200], future.get().status);
+  ASSERT_EQ("chunked", future.get().headers["Transfer-Encoding"]);
+  ASSERT_EQ("Hello World\n", future.get().body);
+
+  terminate(process);
+  wait(process);
+}
+
+
+TEST(HTTP, Encode)
+{
+  std::string unencoded = "a$&+,/:;=?@ \"<>#%{}|\\^~[]`\x19\x80\xFF";
+  unencoded += std::string("\x00", 1); // Add a null byte to the end.
+
+  std::string encoded = http::encode(unencoded);
+
+  EXPECT_EQ("a%24%26%2B%2C%2F%3A%3B%3D%3F%40%20%22%3C%3E%23"
+            "%25%7B%7D%7C%5C%5E%7E%5B%5D%60%19%80%FF%00",
+            encoded);
+
+  EXPECT_SOME_EQ(unencoded, http::decode(encoded));
+
+  EXPECT_ERROR(http::decode("%"));
+  EXPECT_ERROR(http::decode("%1"));
+  EXPECT_ERROR(http::decode("%;1"));
+  EXPECT_ERROR(http::decode("%1;"));
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/tests/io_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/io_tests.cpp b/3rdparty/libprocess/src/tests/io_tests.cpp
new file mode 100644
index 0000000..288fa83
--- /dev/null
+++ b/3rdparty/libprocess/src/tests/io_tests.cpp
@@ -0,0 +1,162 @@
+#include <gmock/gmock.h>
+
+#include <string>
+
+#include <process/future.hpp>
+#include <process/gtest.hpp>
+#include <process/io.hpp>
+
+#include <stout/gtest.hpp>
+#include <stout/os.hpp>
+
+#include "encoder.hpp"
+
+using namespace process;
+
+using std::string;
+
+
+TEST(IO, Poll)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  int pipes[2];
+  pipe(pipes);
+
+  Future<short> future = io::poll(pipes[0], io::READ);
+
+  EXPECT_FALSE(future.isReady());
+
+  ASSERT_EQ(3, write(pipes[1], "hi", 3));
+
+  AWAIT_EXPECT_EQ(io::READ, future);
+
+  close(pipes[0]);
+  close(pipes[1]);
+}
+
+
+TEST(IO, Read)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  int pipes[2];
+  char data[3];
+
+  // Create a blocking pipe.
+  ASSERT_NE(-1, ::pipe(pipes));
+
+  // Test on a blocking file descriptor.
+  AWAIT_EXPECT_FAILED(io::read(pipes[0], data, 3));
+
+  close(pipes[0]);
+  close(pipes[1]);
+
+  // Test on a closed file descriptor.
+  AWAIT_EXPECT_FAILED(io::read(pipes[0], data, 3));
+
+  // Create a nonblocking pipe.
+  ASSERT_NE(-1, ::pipe(pipes));
+  ASSERT_SOME(os::nonblock(pipes[0]));
+  ASSERT_SOME(os::nonblock(pipes[1]));
+
+  // Test reading nothing.
+  AWAIT_EXPECT_FAILED(io::read(pipes[0], data, 0));
+
+  // Test successful read.
+  Future<size_t> future = io::read(pipes[0], data, 3);
+  ASSERT_FALSE(future.isReady());
+
+  ASSERT_EQ(2, write(pipes[1], "hi", 2));
+
+  AWAIT_ASSERT_EQ(2u, future);
+  EXPECT_EQ('h', data[0]);
+  EXPECT_EQ('i', data[1]);
+
+  // Test cancellation.
+  future = io::read(pipes[0], data, 1);
+  ASSERT_FALSE(future.isReady());
+
+  future.discard();
+
+  ASSERT_EQ(3, write(pipes[1], "omg", 3));
+
+  AWAIT_ASSERT_EQ(3u, io::read(pipes[0], data, 3));
+  EXPECT_EQ('o', data[0]);
+  EXPECT_EQ('m', data[1]);
+  EXPECT_EQ('g', data[2]);
+
+  // Test read EOF.
+  future = io::read(pipes[0], data, 3);
+  ASSERT_FALSE(future.isReady());
+
+  close(pipes[1]);
+
+  AWAIT_ASSERT_EQ(0u, future);
+
+  close(pipes[0]);
+}
+
+
+TEST(IO, BufferedRead)
+{
+  // 128 Bytes.
+  string data =
+      "This data is much larger than BUFFERED_READ_SIZE, which means it will "
+      "trigger multiple buffered async reads as a result.........";
+  ASSERT_EQ(128u, data.size());
+
+  // Keep doubling the data size until we're guaranteed to trigger at least
+  // 3 buffered async reads.
+  while (data.length() < 3 * io::BUFFERED_READ_SIZE) {
+    data.append(data);
+  }
+
+  // First read from a file.
+  ASSERT_SOME(os::write("file", data));
+
+  Try<int> fd = os::open("file", O_RDONLY);
+  ASSERT_SOME(fd);
+
+  // Read from blocking fd.
+  AWAIT_EXPECT_FAILED(io::read(fd.get()));
+
+  // Read from non-blocking fd.
+  ASSERT_TRUE(os::nonblock(fd.get()).isSome());
+  AWAIT_EXPECT_EQ(data, io::read(fd.get()));
+
+  os::close(fd.get());
+
+  // Now read from pipes.
+  int pipes[2];
+
+  // Create a blocking pipe.
+  ASSERT_NE(-1, ::pipe(pipes));
+
+  // Test on a blocking pipe.
+  AWAIT_EXPECT_FAILED(io::read(pipes[0]));
+
+  close(pipes[0]);
+  close(pipes[1]);
+
+  // Test on a closed pipe.
+  AWAIT_EXPECT_FAILED(io::read(pipes[0]));
+
+  // Create a nonblocking pipe for reading.
+  ASSERT_NE(-1, ::pipe(pipes));
+  ASSERT_SOME(os::nonblock(pipes[0]));
+
+  // Test a successful read from the pipe.
+  Future<string> future = io::read(pipes[0]);
+
+  // At first, the future will not be ready until we write to and
+  // close the pipe.
+  ASSERT_FALSE(future.isReady());
+
+  ASSERT_SOME(os::write(pipes[1], data));
+  close(pipes[1]);
+
+  AWAIT_EXPECT_EQ(data, future);
+
+  close(pipes[0]);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/tests/main.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/main.cpp b/3rdparty/libprocess/src/tests/main.cpp
new file mode 100644
index 0000000..6c672b4
--- /dev/null
+++ b/3rdparty/libprocess/src/tests/main.cpp
@@ -0,0 +1,25 @@
+#include <gtest/gtest.h>
+
+#include <gmock/gmock.h>
+
+#include <process/gmock.hpp>
+#include <process/gtest.hpp>
+#include <process/process.hpp>
+
+int main(int argc, char** argv)
+{
+  // Initialize Google Mock/Test.
+  testing::InitGoogleMock(&argc, argv);
+
+  // Initialize libprocess.
+  process::initialize();
+
+  // Add the libprocess test event listeners.
+  ::testing::TestEventListeners& listeners =
+    ::testing::UnitTest::GetInstance()->listeners();
+
+  listeners.Append(process::ClockTestEventListener::instance());
+  listeners.Append(process::FilterTestEventListener::instance());
+
+  return RUN_ALL_TESTS();
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/tests/process_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/process_tests.cpp b/3rdparty/libprocess/src/tests/process_tests.cpp
new file mode 100644
index 0000000..dc5c671
--- /dev/null
+++ b/3rdparty/libprocess/src/tests/process_tests.cpp
@@ -0,0 +1,1143 @@
+#include <arpa/inet.h>
+
+#include <gmock/gmock.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <string>
+#include <sstream>
+
+#include <process/async.hpp>
+#include <process/collect.hpp>
+#include <process/clock.hpp>
+#include <process/defer.hpp>
+#include <process/delay.hpp>
+#include <process/dispatch.hpp>
+#include <process/executor.hpp>
+#include <process/filter.hpp>
+#include <process/future.hpp>
+#include <process/gc.hpp>
+#include <process/gmock.hpp>
+#include <process/gtest.hpp>
+#include <process/process.hpp>
+#include <process/run.hpp>
+#include <process/thread.hpp>
+#include <process/time.hpp>
+
+#include <stout/duration.hpp>
+#include <stout/nothing.hpp>
+#include <stout/os.hpp>
+#include <stout/stringify.hpp>
+
+#include "encoder.hpp"
+
+using namespace process;
+
+using testing::_;
+using testing::Assign;
+using testing::DoAll;
+using testing::Return;
+using testing::ReturnArg;
+
+// TODO(bmahler): Move tests into their own files as appropriate.
+
+TEST(Process, thread)
+{
+  ThreadLocal<ProcessBase>* _process_ = new ThreadLocal<ProcessBase>();
+
+  ProcessBase* process = new ProcessBase();
+
+  ASSERT_TRUE(*(_process_) == NULL);
+
+  (*_process_) = process;
+
+  ASSERT_TRUE(*(_process_) == process);
+  ASSERT_FALSE(*(_process_) == NULL);
+
+  (*_process_) = NULL;
+
+  ASSERT_TRUE(*(_process_) == NULL);
+
+  delete process;
+  delete _process_;
+}
+
+
+TEST(Process, event)
+{
+  Event* event = new TerminateEvent(UPID());
+  EXPECT_FALSE(event->is<MessageEvent>());
+  EXPECT_FALSE(event->is<ExitedEvent>());
+  EXPECT_TRUE(event->is<TerminateEvent>());
+  delete event;
+}
+
+
+TEST(Process, future)
+{
+  Promise<bool> promise;
+  promise.set(true);
+  ASSERT_TRUE(promise.future().isReady());
+  EXPECT_TRUE(promise.future().get());
+}
+
+
+TEST(Process, associate)
+{
+  Promise<bool> promise1;
+  Future<bool> future1(true);
+  promise1.associate(future1);
+  ASSERT_TRUE(promise1.future().isReady());
+  EXPECT_TRUE(promise1.future().get());
+
+  Promise<bool> promise2;
+  Future<bool> future2;
+  promise2.associate(future2);
+  future2.discard();
+  ASSERT_TRUE(promise2.future().isDiscarded());
+
+  Promise<bool> promise3;
+  Promise<bool> promise4;
+  promise3.associate(promise4.future());
+  promise4.fail("associate");
+  ASSERT_TRUE(promise3.future().isFailed());
+  EXPECT_EQ("associate", promise3.future().failure());
+}
+
+
+void onAny(const Future<bool>& future, bool* b)
+{
+  ASSERT_TRUE(future.isReady());
+  *b = future.get();
+}
+
+
+TEST(Process, onAny)
+{
+  bool b = false;
+  Future<bool>(true)
+    .onAny(std::tr1::bind(&onAny, std::tr1::placeholders::_1, &b));
+  EXPECT_TRUE(b);
+}
+
+
+Future<std::string> itoa1(int* const& i)
+{
+  std::ostringstream out;
+  out << *i;
+  return out.str();
+}
+
+
+std::string itoa2(int* const& i)
+{
+  std::ostringstream out;
+  out << *i;
+  return out.str();
+}
+
+
+TEST(Process, then)
+{
+  Promise<int*> promise;
+
+  int i = 42;
+
+  promise.set(&i);
+
+  Future<std::string> future = promise.future()
+    .then(std::tr1::bind(&itoa1, std::tr1::placeholders::_1));
+
+  ASSERT_TRUE(future.isReady());
+  EXPECT_EQ("42", future.get());
+
+  future = promise.future()
+    .then(std::tr1::bind(&itoa2, std::tr1::placeholders::_1));
+
+  ASSERT_TRUE(future.isReady());
+  EXPECT_EQ("42", future.get());
+}
+
+
+Future<bool> readyFuture()
+{
+  return true;
+}
+
+
+Future<bool> failedFuture()
+{
+  return Future<bool>::failed("The value is not positive (or zero)");
+}
+
+
+Future<bool> pendingFuture(Future<bool>* future)
+{
+  return *future; // Keep it pending.
+}
+
+
+Future<std::string> second(const bool& b)
+{
+  return b ? std::string("true") : std::string("false");
+}
+
+
+Future<std::string> third(const std::string& s)
+{
+  return s;
+}
+
+
+TEST(Process, chain)
+{
+  Promise<int*> promise;
+
+  Future<std::string> s = readyFuture()
+    .then(std::tr1::bind(&second, std::tr1::placeholders::_1))
+    .then(std::tr1::bind(&third, std::tr1::placeholders::_1));
+
+  s.await();
+
+  ASSERT_TRUE(s.isReady());
+  EXPECT_EQ("true", s.get());
+
+  s = failedFuture()
+    .then(std::tr1::bind(&second, std::tr1::placeholders::_1))
+    .then(std::tr1::bind(&third, std::tr1::placeholders::_1));
+
+  s.await();
+
+  ASSERT_TRUE(s.isFailed());
+
+  Future<bool> future;
+
+  s = pendingFuture(&future)
+    .then(std::tr1::bind(&second, std::tr1::placeholders::_1))
+    .then(std::tr1::bind(&third, std::tr1::placeholders::_1));
+
+  ASSERT_TRUE(s.isPending());
+  ASSERT_TRUE(future.isPending());
+
+  s.discard();
+
+  future.await();
+
+  ASSERT_TRUE(future.isDiscarded());
+}
+
+
+class SpawnProcess : public Process<SpawnProcess>
+{
+public:
+  MOCK_METHOD0(initialize, void(void));
+  MOCK_METHOD0(finalize, void(void));
+};
+
+
+TEST(Process, spawn)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  SpawnProcess process;
+
+  EXPECT_CALL(process, initialize())
+    .Times(1);
+
+  EXPECT_CALL(process, finalize())
+    .Times(1);
+
+  PID<SpawnProcess> pid = spawn(process);
+
+  ASSERT_FALSE(!pid);
+
+  ASSERT_FALSE(wait(pid, Seconds(0)));
+
+  terminate(pid);
+  wait(pid);
+}
+
+
+class DispatchProcess : public Process<DispatchProcess>
+{
+public:
+  MOCK_METHOD0(func0, void(void));
+  MOCK_METHOD1(func1, bool(bool));
+  MOCK_METHOD1(func2, Future<bool>(bool));
+  MOCK_METHOD1(func3, int(int));
+  MOCK_METHOD2(func4, Future<bool>(bool, int));
+};
+
+
+TEST(Process, dispatch)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  DispatchProcess process;
+
+  EXPECT_CALL(process, func0())
+    .Times(1);
+
+  EXPECT_CALL(process, func1(_))
+    .WillOnce(ReturnArg<0>());
+
+  EXPECT_CALL(process, func2(_))
+    .WillOnce(ReturnArg<0>());
+
+  PID<DispatchProcess> pid = spawn(&process);
+
+  ASSERT_FALSE(!pid);
+
+  dispatch(pid, &DispatchProcess::func0);
+
+  Future<bool> future;
+
+  future = dispatch(pid, &DispatchProcess::func1, true);
+
+  EXPECT_TRUE(future.get());
+
+  future = dispatch(pid, &DispatchProcess::func2, true);
+
+  EXPECT_TRUE(future.get());
+
+  terminate(pid);
+  wait(pid);
+}
+
+
+TEST(Process, defer1)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  DispatchProcess process;
+
+  EXPECT_CALL(process, func0())
+    .Times(1);
+
+  EXPECT_CALL(process, func1(_))
+    .WillOnce(ReturnArg<0>());
+
+  EXPECT_CALL(process, func2(_))
+    .WillOnce(ReturnArg<0>());
+
+  EXPECT_CALL(process, func4(_, _))
+    .WillRepeatedly(ReturnArg<0>());
+
+  PID<DispatchProcess> pid = spawn(&process);
+
+  ASSERT_FALSE(!pid);
+
+  {
+    Deferred<void(void)> func0 =
+      defer(pid, &DispatchProcess::func0);
+    func0();
+  }
+
+  Future<bool> future;
+
+  {
+    Deferred<Future<bool>(void)> func1 =
+      defer(pid, &DispatchProcess::func1, true);
+    future = func1();
+    EXPECT_TRUE(future.get());
+  }
+
+  {
+    Deferred<Future<bool>(void)> func2 =
+      defer(pid, &DispatchProcess::func2, true);
+    future = func2();
+    EXPECT_TRUE(future.get());
+  }
+
+  {
+    Deferred<Future<bool>(void)> func4 =
+      defer(pid, &DispatchProcess::func4, true, 42);
+    future = func4();
+    EXPECT_TRUE(future.get());
+  }
+
+  {
+    Deferred<Future<bool>(bool)> func4 =
+      defer(pid, &DispatchProcess::func4, std::tr1::placeholders::_1, 42);
+    future = func4(false);
+    EXPECT_FALSE(future.get());
+  }
+
+  {
+    Deferred<Future<bool>(int)> func4 =
+      defer(pid, &DispatchProcess::func4, true, std::tr1::placeholders::_1);
+    future = func4(42);
+    EXPECT_TRUE(future.get());
+  }
+
+  // Only take const &!
+
+  terminate(pid);
+  wait(pid);
+}
+
+
+class DeferProcess : public Process<DeferProcess>
+{
+public:
+  Future<std::string> func1(const Future<int>& f)
+  {
+    return f.then(defer(self(), &Self::_func1, std::tr1::placeholders::_1));
+  }
+
+  Future<std::string> func2(const Future<int>& f)
+  {
+    return f.then(defer(self(), &Self::_func2));
+  }
+
+private:
+  Future<std::string> _func1(int i)
+  {
+    return stringify(i);
+  }
+
+  Future<std::string> _func2()
+  {
+    return std::string("42");
+  }
+};
+
+
+TEST(Process, defer2)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  DeferProcess process;
+
+  PID<DeferProcess> pid = spawn(process);
+
+  Future<std::string> f = dispatch(pid, &DeferProcess::func1, 41);
+
+  f.await();
+
+  ASSERT_TRUE(f.isReady());
+  EXPECT_EQ("41", f.get());
+
+  f = dispatch(pid, &DeferProcess::func2, 41);
+
+  f.await();
+
+  ASSERT_TRUE(f.isReady());
+  EXPECT_EQ("42", f.get());
+
+  terminate(pid);
+  wait(pid);
+}
+
+
+template <typename T>
+void set(T* t1, const T& t2)
+{
+  *t1 = t2;
+}
+
+
+TEST(Process, defer3)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  volatile bool bool1 = false;
+  volatile bool bool2 = false;
+
+  Deferred<void(bool)> set1 =
+    defer(std::tr1::function<void(bool)>(
+              std::tr1::bind(&set<volatile bool>,
+                             &bool1,
+                             std::tr1::placeholders::_1)));
+
+  set1(true);
+
+  Deferred<void(bool)> set2 =
+    defer(std::tr1::function<void(bool)>(
+              std::tr1::bind(&set<volatile bool>,
+                             &bool2,
+                             std::tr1::placeholders::_1)));
+
+  set2(true);
+
+  while (!bool1);
+  while (!bool2);
+}
+
+
+class HandlersProcess : public Process<HandlersProcess>
+{
+public:
+  HandlersProcess()
+  {
+    install("func", &HandlersProcess::func);
+  }
+
+  MOCK_METHOD2(func, void(const UPID&, const std::string&));
+};
+
+
+TEST(Process, handlers)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  HandlersProcess process;
+
+  EXPECT_CALL(process, func(_, _))
+    .Times(1);
+
+  PID<HandlersProcess> pid = spawn(&process);
+
+  ASSERT_FALSE(!pid);
+
+  post(pid, "func");
+
+  terminate(pid, false);
+  wait(pid);
+}
+
+
+// Tests EXPECT_MESSAGE and EXPECT_DISPATCH and in particular that an
+// event can get dropped before being processed.
+TEST(Process, expect)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  HandlersProcess process;
+
+  EXPECT_CALL(process, func(_, _))
+    .Times(0);
+
+  PID<HandlersProcess> pid = spawn(&process);
+
+  ASSERT_FALSE(!pid);
+
+  Future<Message> message = DROP_MESSAGE("func", _, _);
+
+  post(pid, "func");
+
+  AWAIT_EXPECT_READY(message);
+
+  Future<Nothing> func = DROP_DISPATCH(pid, &HandlersProcess::func);
+
+  dispatch(pid, &HandlersProcess::func, pid, "");
+
+  AWAIT_EXPECT_READY(func);
+
+  terminate(pid, false);
+  wait(pid);
+}
+
+
+// Tests the FutureArg<N> action.
+TEST(Process, action)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  HandlersProcess process;
+
+  PID<HandlersProcess> pid = spawn(&process);
+
+  ASSERT_FALSE(!pid);
+
+  Future<std::string> future1;
+  Future<Nothing> future2;
+  EXPECT_CALL(process, func(_, _))
+    .WillOnce(FutureArg<1>(&future1))
+    .WillOnce(FutureSatisfy(&future2));
+
+  dispatch(pid, &HandlersProcess::func, pid, "hello world");
+
+  AWAIT_EXPECT_EQ("hello world", future1);
+
+  EXPECT_TRUE(future2.isPending());
+
+  dispatch(pid, &HandlersProcess::func, pid, "hello world");
+
+  AWAIT_EXPECT_READY(future2);
+
+  terminate(pid, false);
+  wait(pid);
+}
+
+
+class BaseProcess : public Process<BaseProcess>
+{
+public:
+  virtual void func() = 0;
+  MOCK_METHOD0(foo, void());
+};
+
+
+class DerivedProcess : public BaseProcess
+{
+public:
+  DerivedProcess() {}
+  MOCK_METHOD0(func, void());
+};
+
+
+TEST(Process, inheritance)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  DerivedProcess process;
+
+  EXPECT_CALL(process, func())
+    .Times(2);
+
+  EXPECT_CALL(process, foo())
+    .Times(1);
+
+  PID<DerivedProcess> pid1 = spawn(&process);
+
+  ASSERT_FALSE(!pid1);
+
+  dispatch(pid1, &DerivedProcess::func);
+
+  PID<BaseProcess> pid2(process);
+  PID<BaseProcess> pid3 = pid1;
+
+  ASSERT_EQ(pid2, pid3);
+
+  dispatch(pid3, &BaseProcess::func);
+  dispatch(pid3, &BaseProcess::foo);
+
+  terminate(pid1, false);
+  wait(pid1);
+}
+
+
+TEST(Process, thunk)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  struct Thunk
+  {
+    static int run(int i)
+    {
+      return i;
+    }
+
+    static int run(int i, int j)
+    {
+      return run(i + j);
+    }
+  };
+
+  int result = run(&Thunk::run, 21, 21).get();
+
+  EXPECT_EQ(42, result);
+}
+
+
+class DelegatorProcess : public Process<DelegatorProcess>
+{
+public:
+  DelegatorProcess(const UPID& delegatee)
+  {
+    delegate("func", delegatee);
+  }
+};
+
+
+class DelegateeProcess : public Process<DelegateeProcess>
+{
+public:
+  DelegateeProcess()
+  {
+    install("func", &DelegateeProcess::func);
+  }
+
+  MOCK_METHOD2(func, void(const UPID&, const std::string&));
+};
+
+
+TEST(Process, delegate)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  DelegateeProcess delegatee;
+  DelegatorProcess delegator(delegatee.self());
+
+  EXPECT_CALL(delegatee, func(_, _))
+    .Times(1);
+
+  spawn(&delegator);
+  spawn(&delegatee);
+
+  post(delegator.self(), "func");
+
+  terminate(delegator, false);
+  wait(delegator);
+
+  terminate(delegatee, false);
+  wait(delegatee);
+}
+
+
+class TimeoutProcess : public Process<TimeoutProcess>
+{
+public:
+  MOCK_METHOD0(timeout, void());
+};
+
+
+TEST(Process, delay)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  Clock::pause();
+
+  volatile bool timeoutCalled = false;
+
+  TimeoutProcess process;
+
+  EXPECT_CALL(process, timeout())
+    .WillOnce(Assign(&timeoutCalled, true));
+
+  spawn(process);
+
+  delay(Seconds(5), process.self(), &TimeoutProcess::timeout);
+
+  Clock::advance(Seconds(5));
+
+  while (!timeoutCalled);
+
+  terminate(process);
+  wait(process);
+
+  Clock::resume();
+}
+
+
+class OrderProcess : public Process<OrderProcess>
+{
+public:
+  void order(const PID<TimeoutProcess>& pid)
+  {
+    // TODO(benh): Add a test which uses 'send' instead of dispatch.
+    dispatch(pid, &TimeoutProcess::timeout);
+  }
+};
+
+
+TEST(Process, order)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  Clock::pause();
+
+  TimeoutProcess process1;
+
+  volatile bool timeoutCalled = false;
+
+  EXPECT_CALL(process1, timeout())
+    .WillOnce(Assign(&timeoutCalled, true));
+
+  spawn(process1);
+
+  Time now = Clock::now(&process1);
+
+  Seconds seconds(1);
+
+  Clock::advance(Seconds(1));
+
+  EXPECT_EQ(now, Clock::now(&process1));
+
+  OrderProcess process2;
+  spawn(process2);
+
+  dispatch(process2, &OrderProcess::order, process1.self());
+
+  while (!timeoutCalled);
+
+  EXPECT_EQ(now + seconds, Clock::now(&process1));
+
+  terminate(process1);
+  wait(process1);
+
+  terminate(process2);
+  wait(process2);
+
+  Clock::resume();
+}
+
+
+class DonateProcess : public Process<DonateProcess>
+{
+public:
+  void donate()
+  {
+    DonateProcess process;
+    spawn(process);
+    terminate(process);
+    wait(process);
+  }
+};
+
+
+TEST(Process, donate)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  DonateProcess process;
+  spawn(process);
+
+  dispatch(process, &DonateProcess::donate);
+
+  terminate(process, false);
+  wait(process);
+}
+
+
+class ExitedProcess : public Process<ExitedProcess>
+{
+public:
+  ExitedProcess(const UPID& pid) { link(pid); }
+
+  MOCK_METHOD1(exited, void(const UPID&));
+};
+
+
+TEST(Process, exited)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  UPID pid = spawn(new ProcessBase(), true);
+
+  ExitedProcess process(pid);
+
+  volatile bool exitedCalled = false;
+
+  EXPECT_CALL(process, exited(pid))
+    .WillOnce(Assign(&exitedCalled, true));
+
+  spawn(process);
+
+  terminate(pid);
+
+  while (!exitedCalled);
+
+  terminate(process);
+  wait(process);
+}
+
+
+TEST(Process, select)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  Promise<int> promise1;
+  Promise<int> promise2;
+  Promise<int> promise3;
+  Promise<int> promise4;
+
+  std::set<Future<int> > futures;
+  futures.insert(promise1.future());
+  futures.insert(promise2.future());
+  futures.insert(promise3.future());
+  futures.insert(promise4.future());
+
+  promise1.set(42);
+
+  Future<Future<int> > future = select(futures);
+
+  EXPECT_TRUE(future.await());
+  EXPECT_TRUE(future.isReady());
+  EXPECT_TRUE(future.get().isReady());
+  EXPECT_EQ(42, future.get().get());
+}
+
+
+TEST(Process, collect)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  Promise<int> promise1;
+  Promise<int> promise2;
+  Promise<int> promise3;
+  Promise<int> promise4;
+
+  std::list<Future<int> > futures;
+  futures.push_back(promise1.future());
+  futures.push_back(promise2.future());
+  futures.push_back(promise3.future());
+  futures.push_back(promise4.future());
+
+  promise1.set(1);
+  promise2.set(2);
+  promise3.set(3);
+  promise4.set(4);
+
+  Future<std::list<int> > future = collect(futures);
+
+  EXPECT_TRUE(future.await());
+  EXPECT_TRUE(future.isReady());
+
+  std::list<int> values;
+  values.push_back(1);
+  values.push_back(2);
+  values.push_back(3);
+  values.push_back(4);
+
+  EXPECT_EQ(values, future.get());
+}
+
+
+class SettleProcess : public Process<SettleProcess>
+{
+public:
+  SettleProcess() : calledDispatch(false) {}
+
+  virtual void initialize()
+  {
+    os::sleep(Milliseconds(10));
+    delay(Seconds(0), self(), &SettleProcess::afterDelay);
+  }
+
+  void afterDelay()
+  {
+    dispatch(self(), &SettleProcess::afterDispatch);
+    os::sleep(Milliseconds(10));
+    TimeoutProcess timeoutProcess;
+    spawn(timeoutProcess);
+    terminate(timeoutProcess);
+    wait(timeoutProcess);
+  }
+
+  void afterDispatch()
+  {
+    os::sleep(Milliseconds(10));
+    calledDispatch = true;
+  }
+
+  volatile bool calledDispatch;
+};
+
+
+TEST(Process, settle)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  Clock::pause();
+  SettleProcess process;
+  spawn(process);
+  Clock::settle();
+  ASSERT_TRUE(process.calledDispatch);
+  terminate(process);
+  wait(process);
+  Clock::resume();
+}
+
+
+TEST(Process, pid)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  TimeoutProcess process;
+
+  PID<TimeoutProcess> pid = process;
+}
+
+
+class Listener1 : public Process<Listener1>
+{
+public:
+  virtual void event1() = 0;
+};
+
+
+class Listener2 : public Process<Listener2>
+{
+public:
+  virtual void event2() = 0;
+};
+
+
+class MultipleListenerProcess
+  : public Process<MultipleListenerProcess>,
+    public Listener1,
+    public Listener2
+{
+public:
+  MOCK_METHOD0(event1, void());
+  MOCK_METHOD0(event2, void());
+};
+
+
+TEST(Process, listener)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  MultipleListenerProcess process;
+
+  EXPECT_CALL(process, event1())
+    .Times(1);
+
+  EXPECT_CALL(process, event2())
+    .Times(1);
+
+  spawn(process);
+
+  dispatch(PID<Listener1>(process), &Listener1::event1);
+  dispatch(PID<Listener2>(process), &Listener2::event2);
+
+  terminate(process, false);
+  wait(process);
+}
+
+
+class EventReceiver
+{
+public:
+  MOCK_METHOD1(event1, void(int));
+  MOCK_METHOD1(event2, void(const std::string&));
+};
+
+
+TEST(Process, executor)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  volatile bool event1Called = false;
+  volatile bool event2Called = false;
+
+  EventReceiver receiver;
+
+  EXPECT_CALL(receiver, event1(42))
+    .WillOnce(Assign(&event1Called, true));
+
+  EXPECT_CALL(receiver, event2("event2"))
+    .WillOnce(Assign(&event2Called, true));
+
+  Executor executor;
+
+  Deferred<void(int)> event1 =
+    executor.defer(std::tr1::bind(&EventReceiver::event1,
+                                  &receiver,
+                                  std::tr1::placeholders::_1));
+
+  event1(42);
+
+  Deferred<void(const std::string&)> event2 =
+    executor.defer(std::tr1::bind(&EventReceiver::event2,
+                                  &receiver,
+                                  std::tr1::placeholders::_1));
+
+  event2("event2");
+
+  while (!event1Called);
+  while (!event2Called);
+}
+
+
+class RemoteProcess : public Process<RemoteProcess>
+{
+public:
+  RemoteProcess()
+  {
+    install("handler", &RemoteProcess::handler);
+  }
+
+  MOCK_METHOD2(handler, void(const UPID&, const std::string&));
+};
+
+
+TEST(Process, remote)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  RemoteProcess process;
+
+  volatile bool handlerCalled = false;
+
+  EXPECT_CALL(process, handler(_, _))
+    .WillOnce(Assign(&handlerCalled, true));
+
+  spawn(process);
+
+  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+
+  ASSERT_LE(0, s);
+
+  sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = PF_INET;
+  addr.sin_port = htons(process.self().port);
+  addr.sin_addr.s_addr = process.self().ip;
+
+  ASSERT_EQ(0, connect(s, (sockaddr*) &addr, sizeof(addr)));
+
+  Message message;
+  message.name = "handler";
+  message.from = UPID();
+  message.to = process.self();
+
+  const std::string& data = MessageEncoder::encode(&message);
+
+  ASSERT_EQ(data.size(), write(s, data.data(), data.size()));
+
+  ASSERT_EQ(0, close(s));
+
+  while (!handlerCalled);
+
+  terminate(process);
+  wait(process);
+}
+
+
+int foo()
+{
+  return 1;
+}
+
+int foo1(int a)
+{
+  return a;
+}
+
+
+int foo2(int a, int b)
+{
+  return a + b;
+}
+
+
+int foo3(int a, int b, int c)
+{
+  return a + b + c;
+}
+
+
+int foo4(int a, int b, int c, int d)
+{
+  return a + b + c + d;
+}
+
+
+void bar(int a)
+{
+  return;
+}
+
+
+TEST(Process, async)
+{
+  ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+  // Non-void functions with different no.of args.
+  EXPECT_EQ(1, async(&foo).get());
+  EXPECT_EQ(10, async(&foo1, 10).get());
+  EXPECT_EQ(30, async(&foo2, 10, 20).get());
+  EXPECT_EQ(60, async(&foo3, 10, 20, 30).get());
+  EXPECT_EQ(100, async(&foo4, 10, 20, 30, 40).get());
+
+  // Non-void function with a complex arg.
+  int i = 42;
+  EXPECT_EQ("42", async(&itoa2, &i).get());
+
+  // Non-void function that returns a future.
+  EXPECT_EQ("42", async(&itoa1, &i).get().get());
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/tests/statistics_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/statistics_tests.cpp b/3rdparty/libprocess/src/tests/statistics_tests.cpp
new file mode 100644
index 0000000..8695f45
--- /dev/null
+++ b/3rdparty/libprocess/src/tests/statistics_tests.cpp
@@ -0,0 +1,184 @@
+#include <gmock/gmock.h>
+
+#include <map>
+
+#include <process/clock.hpp>
+#include <process/future.hpp>
+#include <process/gtest.hpp>
+#include <process/statistics.hpp>
+#include <process/time.hpp>
+
+#include <stout/duration.hpp>
+
+using namespace process;
+
+using std::map;
+
+
+TEST(Statistics, set)
+{
+  Statistics statistics(Days(1));
+
+  // Set one using Clock::now() implicitly.
+  statistics.set("test", "statistic", 3.0);
+
+  // Set one using Clock::now() explicitly.
+  Time now = Clock::now();
+  statistics.set("test", "statistic", 4.0, now);
+
+  Future<map<Time, double> > values =
+    statistics.timeseries("test", "statistic");
+
+  AWAIT_ASSERT_READY(values);
+
+  EXPECT_EQ(2, values.get().size());
+
+  EXPECT_GE(Clock::now(), values.get().begin()->first);
+  EXPECT_DOUBLE_EQ(3.0, values.get().begin()->second);
+
+  EXPECT_EQ(1, values.get().count(now));
+  EXPECT_DOUBLE_EQ(4.0, values.get()[now]);
+}
+
+
+TEST(Statistics, truncate)
+{
+  Clock::pause();
+
+  Statistics statistics(Days(1));
+
+  statistics.set("test", "statistic", 3.0);
+
+  Future<map<Time, double> > values =
+    statistics.timeseries("test", "statistic");
+
+  AWAIT_ASSERT_READY(values);
+
+  EXPECT_EQ(1, values.get().size());
+  EXPECT_GE(Clock::now(), values.get().begin()->first);
+  EXPECT_DOUBLE_EQ(3.0, values.get().begin()->second);
+
+  Clock::advance(Days(1) + Seconds(1));
+  Clock::settle();
+
+  statistics.increment("test", "statistic");
+
+  values = statistics.timeseries("test", "statistic");
+
+  AWAIT_ASSERT_READY(values);
+
+  EXPECT_EQ(1, values.get().size());
+  EXPECT_GE(Clock::now(), values.get().begin()->first);
+  EXPECT_DOUBLE_EQ(4.0, values.get().begin()->second);
+
+  Clock::resume();
+}
+
+
+TEST(Statistics, meter) {
+  Statistics statistics(Days(1));
+
+  // Set up a meter, and ensure it captures the expected time rate.
+  Future<Try<Nothing> > meter =
+    statistics.meter("test", "statistic", new meters::TimeRate("metered"));
+
+  AWAIT_ASSERT_READY(meter);
+
+  ASSERT_TRUE(meter.get().isSome());
+
+  Time now = Clock::now();
+  statistics.set("test", "statistic", 1.0, now);
+  statistics.set("test", "statistic", 2.0, Time(now + Seconds(1)));
+  statistics.set("test", "statistic", 4.0, Time(now + Seconds(2)));
+
+  // Check the raw statistic values.
+  Future<map<Time, double> > values =
+    statistics.timeseries("test", "statistic");
+
+  AWAIT_ASSERT_READY(values);
+
+  EXPECT_EQ(3, values.get().size());
+  EXPECT_EQ(1, values.get().count(now));
+  EXPECT_EQ(1, values.get().count(Time(now + Seconds(1))));
+  EXPECT_EQ(1, values.get().count(Time(now + Seconds(2))));
+
+  EXPECT_EQ(1.0, values.get()[now]);
+  EXPECT_EQ(2.0, values.get()[Time(now + Seconds(1))]);
+  EXPECT_EQ(4.0, values.get()[Time(now + Seconds(2))]);
+
+  // Now check the metered values.
+  values = statistics.timeseries("test", "metered");
+
+  AWAIT_ASSERT_READY(values);
+
+  EXPECT_EQ(2, values.get().size());
+  EXPECT_EQ(1, values.get().count(Time(now + Seconds(1))));
+  EXPECT_EQ(1, values.get().count(Time(now + Seconds(2))));
+
+  EXPECT_EQ(0., values.get()[now]);
+  EXPECT_EQ(1.0, values.get()[Time(now + Seconds(1))]); // 100%.
+  EXPECT_EQ(2.0, values.get()[Time(now + Seconds(2))]); // 200%.
+}
+
+
+TEST(Statistics, archive)
+{
+  Clock::pause();
+
+  Statistics statistics(Seconds(10));
+
+  // Create a meter and a statistic for archival.
+  // Set up a meter, and ensure it captures the expected time rate.
+  Future<Try<Nothing> > meter =
+    statistics.meter("test", "statistic", new meters::TimeRate("metered"));
+
+  AWAIT_ASSERT_READY(meter);
+
+  ASSERT_TRUE(meter.get().isSome());
+
+  Time now = Clock::now();
+  statistics.set("test", "statistic", 1.0, now);
+  statistics.set("test", "statistic", 2.0, Time(now + Seconds(1)));
+
+  // Archive and ensure the following:
+  //   1. The statistic will no longer be part of the snapshot.
+  //   2. Any meters associated with this statistic will be removed.
+  //   3. However, the time series will be retained until the window expiration.
+  statistics.archive("test", "statistic");
+
+  // TODO(bmahler): Wait for JSON parsing to verify number 1.
+
+  // Ensure the raw time series is present.
+  Future<map<Time, double> > values =
+    statistics.timeseries("test", "statistic");
+  AWAIT_ASSERT_READY(values);
+  EXPECT_FALSE(values.get().empty());
+
+  // Ensure the metered timeseries is present.
+  values = statistics.timeseries("test", "metered");
+  AWAIT_ASSERT_READY(values);
+  EXPECT_FALSE(values.get().empty());
+
+  // Expire the window and ensure the statistics were removed.
+  Clock::advance(STATISTICS_TRUNCATION_INTERVAL);
+  Clock::settle();
+
+  // Ensure the raw statistics are gone.
+  values = statistics.timeseries("test", "statistic");
+  AWAIT_ASSERT_READY(values);
+  EXPECT_TRUE(values.get().empty());
+
+  // Ensure the metered statistics are gone.
+  values = statistics.timeseries("test", "metered");
+  AWAIT_ASSERT_READY(values);
+  EXPECT_TRUE(values.get().empty());
+
+  // Reactivate the statistic, and make sure the meter is still missing.
+  statistics.set("test", "statistic", 1.0, now);
+
+  values = statistics.timeseries("test", "metered");
+  AWAIT_ASSERT_READY(values);
+  EXPECT_TRUE(values.get().empty());
+
+  Clock::resume();
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/tests/time_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/time_tests.cpp b/3rdparty/libprocess/src/tests/time_tests.cpp
new file mode 100644
index 0000000..a25827e
--- /dev/null
+++ b/3rdparty/libprocess/src/tests/time_tests.cpp
@@ -0,0 +1,46 @@
+#include <gtest/gtest.h>
+
+#include <gmock/gmock.h>
+
+#include <process/clock.hpp>
+#include <process/time.hpp>
+
+#include <stout/duration.hpp>
+#include <stout/gtest.hpp>
+#include <stout/os.hpp>
+
+using namespace process;
+
+
+TEST(TimeTest, Arithmetic)
+{
+  Time t = Time::EPOCH + Weeks(1000);
+  t -= Weeks(1);
+  EXPECT_EQ(Time::EPOCH + Weeks(999), t);
+
+  t += Weeks(2);
+  EXPECT_EQ(Time::EPOCH + Weeks(1001), t);
+
+  EXPECT_EQ(t, Time::EPOCH + Weeks(1000) + Weeks(1));
+  EXPECT_EQ(t, Time::EPOCH + Weeks(1002) - Weeks(1));
+
+  EXPECT_EQ(Weeks(1), (Time::EPOCH + Weeks(1000)) - (Time::EPOCH + Weeks(999)));
+}
+
+
+TEST(TimeTest, Now)
+{
+  Time t1 = Clock::now();
+  os::sleep(Microseconds(10));
+  ASSERT_LT(Microseconds(10), Clock::now() - t1);
+}
+
+
+TEST(TimeTest, Output)
+{
+  EXPECT_EQ("1989-03-02 00:00:00+00:00", stringify(Time::EPOCH + Weeks(1000)));
+  EXPECT_EQ("1989-03-02 00:00:00.000000001+00:00",
+            stringify(Time::EPOCH + Weeks(1000) + Nanoseconds(1)));
+  EXPECT_EQ("1989-03-02 00:00:00.000001000+00:00",
+            stringify(Time::EPOCH + Weeks(1000) + Microseconds(1)));
+}

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/timer.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/timer.cpp b/3rdparty/libprocess/src/timer.cpp
new file mode 100644
index 0000000..63c5ac1
--- /dev/null
+++ b/3rdparty/libprocess/src/timer.cpp
@@ -0,0 +1,56 @@
+#include <process/timer.hpp>
+
+#include "timeout.hpp"
+
+namespace process {
+
+class TimerProcess : public Process<TimerProcess>
+{
+public:
+  TimerProcess(double _secs,
+               const UPID& _pid,
+               std::tr1::function<void(ProcessBase*)>* _dispatcher)
+    : secs(_secs), pid(_pid), dispatcher(_dispatcher) {}
+
+protected:
+  virtual void operator () ()
+  {
+    if (receive(secs) == TIMEOUT) {
+      internal::dispatch(pid, dispatcher);
+    } else {
+      delete dispatcher;
+    }
+  }
+
+private:
+  const double secs;
+  const UPID pid;
+  std::tr1::function<void(ProcessBase*)>* dispatcher;
+};
+
+
+static void dispatch()
+
+
+Timer::Timer(double secs,
+             const UPID& pid,
+             std::tr1::function<void(ProcessBase*)>* dispatcher)
+{
+  timer = spawn(new TimerProcess(secs, pid, dispatcher), true);
+}
+
+
+Timer::~Timer()
+{
+  // NOTE: Do not terminate the timer! Some users will simply ignore
+  // saving the timer because they never want to cancel, thus
+  // we can not terminate it here!
+}
+
+
+void Timer::cancel()
+{
+  timeouts::cancel(timeout);
+}
+
+} // namespace process {

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/libprocess/src/timer.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/timer.hpp b/3rdparty/libprocess/src/timer.hpp
new file mode 100644
index 0000000..443b5a0
--- /dev/null
+++ b/3rdparty/libprocess/src/timer.hpp
@@ -0,0 +1,125 @@
+#ifndef TIMER_HPP
+#define TIMER_HPP
+
+#include <ctime>
+#include <iostream>
+#include <iomanip>
+
+class timer
+{
+  friend std::ostream& operator<<(std::ostream& os, timer& t);
+
+private:
+  bool running;
+  clock_t start_clock;
+  time_t start_time;
+  double acc_time;
+
+  double elapsed_time();
+
+public:
+  // 'running' is initially false.  A timer needs to be explicitly started
+  // using 'start' or 'restart'
+  timer() : running(false), start_clock(0), start_time(0), acc_time(0) { }
+
+  void start(const char* msg = 0);
+  void restart(const char* msg = 0);
+  void stop(const char* msg = 0);
+  void check(const char* msg = 0);
+
+}; // class timer
+
+//===========================================================================
+// Return the total time that the timer has been in the "running"
+// state since it was first "started" or last "restarted".  For
+// "short" time periods (less than an hour), the actual cpu time
+// used is reported instead of the elapsed time.
+
+inline double timer::elapsed_time()
+{
+  time_t acc_sec = time(0) - start_time;
+  if (acc_sec < 3600)
+    return (clock() - start_clock) / (1.0 * CLOCKS_PER_SEC);
+  else
+    return (1.0 * acc_sec);
+
+} // timer::elapsed_time
+
+//===========================================================================
+// Start a timer.  If it is already running, let it continue running.
+// Print an optional message.
+
+inline void timer::start(const char* msg)
+{
+  // Print an optional message, something like "Starting timer t";
+  if (msg) std::cout << msg << std::endl;
+
+  // Return immediately if the timer is already running
+  if (running) return;
+
+  // Set timer status to running and set the start time
+  running = true;
+  start_clock = clock();
+  start_time = time(0);
+
+} // timer::start
+
+//===========================================================================
+// Turn the timer off and start it again from 0.  Print an optional message.
+
+inline void timer::restart(const char* msg)
+{
+  // Print an optional message, something like "Restarting timer t";
+  if (msg) std::cout << msg << std::endl;
+
+  // Set timer status to running, reset accumulated time, and set start time
+  running = true;
+  acc_time = 0;
+  start_clock = clock();
+  start_time = time(0);
+
+} // timer::restart
+
+//===========================================================================
+// Stop the timer and print an optional message.
+
+inline void timer::stop(const char* msg)
+{
+  // Print an optional message, something like "Stopping timer t";
+  if (msg) std::cout << msg << std::endl;
+
+  // Compute accumulated running time and set timer status to not running
+  if (running) acc_time += elapsed_time();
+  running = false;
+
+} // timer::stop
+
+//===========================================================================
+// Print out an optional message followed by the current timer timing.
+
+inline void timer::check(const char* msg)
+{
+  // Print an optional message, something like "Checking timer t";
+  if (msg) std::cout << msg << " : ";
+
+  std::cout << "Elapsed time [" << std::setiosflags(std::ios::fixed)
+            << std::setprecision(2)
+            << acc_time + (running ? elapsed_time() : 0) << "] seconds\n";
+
+} // timer::check
+
+//===========================================================================
+// Allow timers to be printed to ostreams using the syntax 'os << t'
+// for an ostream 'os' and a timer 't'.  For example, "cout << t" will
+// print out the total amount of time 't' has been "running".
+
+inline std::ostream& operator<<(std::ostream& os, timer& t)
+{
+  os << std::setprecision(2) << std::setiosflags(std::ios::fixed)
+     << t.acc_time + (t.running ? t.elapsed_time() : 0);
+  return os;
+}
+
+//===========================================================================
+
+#endif /* TIMER_HPP */

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/versions.am
----------------------------------------------------------------------
diff --git a/3rdparty/versions.am b/3rdparty/versions.am
new file mode 100644
index 0000000..5932e1f
--- /dev/null
+++ b/3rdparty/versions.am
@@ -0,0 +1,24 @@
+# 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
+
+# This automake utility file is included from 3rdparty/Makefile.am
+# and src/Makefile.am, so we can update the version numbers of
+# third-party packages in exactly one place. For now, however, we
+# still need to update version numbers in src/python/setup.py.in too!
+
+BOTO_VERSION = 2.0b2
+DISTRIBUTE_VERSION = 0.6.26
+ZOOKEEPER_VERSION = 3.3.4

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/3rdparty/zookeeper-3.3.4.tar.gz
----------------------------------------------------------------------
diff --git a/3rdparty/zookeeper-3.3.4.tar.gz b/3rdparty/zookeeper-3.3.4.tar.gz
new file mode 100644
index 0000000..09d4924
Binary files /dev/null and b/3rdparty/zookeeper-3.3.4.tar.gz differ

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
index 6d9ab63..180e48a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -211,8 +211,8 @@ subcomponents is subject to the terms and conditions of the following
 licenses.
 
 ======================================================================
-For the Boost header files (third_party/boost-1.37.0.tar.gz and
-third_party/libprocess/third_party/boost-1.37.0.tar.gz):
+For the Boost header files
+(3rdparty/libprocess/3rdparty/boost-1.37.0.tar.gz):
 ======================================================================
 
 Boost Software License - Version 1.0 - August 17th, 2003
@@ -241,7 +241,7 @@ DEALINGS IN THE SOFTWARE.
 
 
 ======================================================================
-For boto (third_party/boto-2.0b2.zip):
+For boto (3rdparty/boto-2.0b2.zip):
 ======================================================================
 
 Permission is hereby granted, free of charge, to any person obtaining a
@@ -265,7 +265,7 @@ IN THE SOFTWARE.
 
 
 ======================================================================
-For distribute-0.6.26 (third_party/distribute-0.6.26.tar.gz):
+For distribute-0.6.26 (3rdparty/distribute-0.6.26.tar.gz):
 ======================================================================
 
 PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
@@ -319,8 +319,7 @@ Agreement.
 
 
 ======================================================================
-For glog-0.3.1 (third_party/glog-0.3.1.tar.gz and
-third_party/libprocess/third_party/glog-0.3.1.tar.gz):
+For glog-0.3.1 (3rdparty/libprocess/3rdparty/glog-0.3.1.tar.gz):
 ======================================================================
 
 Copyright (c) 2008, Google Inc.
@@ -391,8 +390,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 ======================================================================
-For gmock-1.6.0 (third_party/gmock-1.6.0.tar.gz and
-third_party/libprocess/third_party/gmock-1.6.0.tar.gz):
+For gmock-1.6.0 (3rdparty/libprocess/3rdparty/gmock-1.6.0.tar.gz):
 ======================================================================
 
 Copyright 2008, Google Inc.
@@ -426,7 +424,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 ======================================================================
-For leveldb (third_party/leveldb.tar.gz):
+For leveldb (3rdparty/leveldb.tar.gz):
 ======================================================================
 
 Copyright (c) 2011 The LevelDB Authors. All rights reserved.
@@ -459,7 +457,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 ======================================================================
-For protobuf-2.3.0 (third_party/protobuf-2.3.0.tar.gz):
+For protobuf-2.3.0
+(3rdparty/libprocess/3rdparty/protobuf-2.3.0.tar.gz):
 ======================================================================
 
 Copyright 2008, Google Inc.
@@ -498,7 +497,7 @@ support library is itself covered by the above license.
 
 
 ======================================================================
-For libev-3.8 (third_party/libprocess/third_party/libev.tar.gz):
+For libev-3.8 (3rdparty/libprocess/3rdparty/libev.tar.gz):
 ======================================================================
 
 All files in libev are Copyright (C)2007,2008,2009 Marc Alexander Lehmann.
@@ -541,7 +540,7 @@ file under either the BSD or the GPL.
 
 ======================================================================
 For http-parser
-(third_party/libprocess/third_party/ry-http-parser-1c3624a.tar.gz):
+(3rdparty/libprocess/3rdparty/ry-http-parser-1c3624a.tar.gz):
 ======================================================================
 
 Copyright 2009,2010 Ryan Dahl <ry...@tinyclouds.org>

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/Makefile.am
----------------------------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
index 3374da4..8e7a32f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,7 +18,7 @@ ACLOCAL_AMFLAGS = -I m4
 
 AUTOMAKE_OPTIONS = foreign
 
-SUBDIRS = . third_party src ec2 hadoop
+SUBDIRS = . 3rdparty src ec2 hadoop
 
 EXTRA_DIST =
 

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/bootstrap
----------------------------------------------------------------------
diff --git a/bootstrap b/bootstrap
index cefc2ab..fe542a0 100755
--- a/bootstrap
+++ b/bootstrap
@@ -10,7 +10,7 @@ fi
 
 # Note that we don't use '--no-recursive' becuase older versions of
 # autoconf/autoreconf bail with that option. Unfortunately this means
-# that we'll modify a lot of files in third_party/libprocess, but that
+# that we'll modify a lot of files in 3rdparty/libprocess, but that
 # may change in the future.
 
 autoreconf --install -Wall --verbose "${@}"

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index c3b5a05..e76f775 100644
--- a/configure.ac
+++ b/configure.ac
@@ -51,15 +51,15 @@ LT_OUTPUT
 AS_IF([test "x${ac_cv_env_CFLAGS_set}" = "x"], [CFLAGS="-g"])
 AS_IF([test "x${ac_cv_env_CXXFLAGS_set}" = "x"], [CXXFLAGS="-g"])
 
-# Save the configure arguments so we can pass them to any third_party
+# Save the configure arguments so we can pass them to any third-party
 # libraries that we might run configure on (see
-# third_party/Makefile.am). One downside of our strategy for shipping
-# and building third_party libraries is that we can't expose options
-# from nested third_party configure scripts.
+# 3rdparty/Makefile.am). One downside of our strategy for shipping and
+# building third-party libraries is that we can't expose options from
+# nested third-party configure scripts.
 CONFIGURE_ARGS="$ac_configure_args"
 AC_SUBST(CONFIGURE_ARGS)
 
-# Force configured third_party libraries (currently only libprocess)
+# Force configured third-party libraries (currently only libprocess)
 # to only build a static library with position independent code so
 # that we can produce a final shared library which includes everything
 # necessary (and only install that).
@@ -74,13 +74,13 @@ ac_configure_args="$ac_configure_args_post"
 AC_CONFIG_COMMANDS_PRE([ac_configure_args="$ac_configure_args_pre"])
 AC_CONFIG_COMMANDS_POST([ac_configure_args="$ac_configure_args_post"])
 
-AC_CONFIG_SUBDIRS([third_party/libprocess])
+AC_CONFIG_SUBDIRS([3rdparty/libprocess])
 
 AC_CONFIG_FILES([Makefile])
 AC_CONFIG_FILES([ec2/Makefile])
 AC_CONFIG_FILES([hadoop/Makefile])
 AC_CONFIG_FILES([src/Makefile])
-AC_CONFIG_FILES([third_party/Makefile])
+AC_CONFIG_FILES([3rdparty/Makefile])
 
 AC_CONFIG_FILES([bin/mesos-build-env.sh])
 AC_CONFIG_FILES([bin/mesos-local.sh], [chmod +x bin/mesos-local.sh])

http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/71a01bd9/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 738c18f..a91daae 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,21 +19,21 @@
 # master/http.cpp and slave/http.cpp.
 AUTOMAKE_OPTIONS = subdir-objects
 
-include ../third_party/versions.am
-include ../third_party/libprocess/third_party/versions.am
+include ../3rdparty/versions.am
+include ../3rdparty/libprocess/3rdparty/versions.am
 
 # TODO(charles): Move these into an included automakefile and have
 # them include $(top_builddir) as appropriate.
-DISTRIBUTE = third_party/distribute-$(DISTRIBUTE_VERSION)
-LEVELDB = third_party/leveldb
-ZOOKEEPER = third_party/zookeeper-$(ZOOKEEPER_VERSION)/src/c
-LIBPROCESS = third_party/libprocess
-STOUT = $(LIBPROCESS)/third_party/stout
-BOOST = $(LIBPROCESS)/third_party/boost-$(BOOST_VERSION)
-GLOG = $(LIBPROCESS)/third_party/glog-$(GLOG_VERSION)
-GMOCK = $(LIBPROCESS)/third_party/gmock-$(GMOCK_VERSION)
+DISTRIBUTE = 3rdparty/distribute-$(DISTRIBUTE_VERSION)
+LEVELDB = 3rdparty/leveldb
+ZOOKEEPER = 3rdparty/zookeeper-$(ZOOKEEPER_VERSION)/src/c
+LIBPROCESS = 3rdparty/libprocess
+STOUT = $(LIBPROCESS)/3rdparty/stout
+BOOST = $(LIBPROCESS)/3rdparty/boost-$(BOOST_VERSION)
+GLOG = $(LIBPROCESS)/3rdparty/glog-$(GLOG_VERSION)
+GMOCK = $(LIBPROCESS)/3rdparty/gmock-$(GMOCK_VERSION)
 GTEST = $(GMOCK)/gtest
-PROTOBUF = $(LIBPROCESS)/third_party/protobuf-$(PROTOBUF_VERSION)
+PROTOBUF = $(LIBPROCESS)/3rdparty/protobuf-$(PROTOBUF_VERSION)
 
 
 # Unfortunatley, 'pkglibexecdir' and 'pkglocalstatedir' are not set
@@ -100,7 +100,7 @@ endif
 # README: we build the Mesos library out of a collection of
 # convenience libraries (that is, libraries that do not get installed
 # but we can use as building blocks to vary compile flags as necessary
-# and then aggregate into final archives): libmesos_no_third_party.la
+# and then aggregate into final archives): libmesos_no_3rdparty.la
 # libbuild.la, liblog.la, libjava.la.
 
 # First, let's define necessary protocol buffer files.
@@ -155,14 +155,14 @@ $(PYTHON_PROTOS): $(MESOS_PROTO)
 # exclude third party libraries so setuptools/distribute can build a
 # self-contained Python library and statically link in the third party
 # libraries themselves.
-noinst_LTLIBRARIES += libmesos_no_third_party.la
+noinst_LTLIBRARIES += libmesos_no_3rdparty.la
 
-nodist_libmesos_no_third_party_la_SOURCES = 	\
+nodist_libmesos_no_3rdparty_la_SOURCES = 	\
   $(CXX_PROTOS) 				\
   $(MESSAGES_PROTOS) 				\
   $(REGISTRY_PROTOS)
 
-libmesos_no_third_party_la_SOURCES =					\
+libmesos_no_3rdparty_la_SOURCES =					\
 	sched/sched.cpp							\
 	local/local.cpp							\
 	master/constants.cpp						\
@@ -203,16 +203,16 @@ pkginclude_HEADERS = $(top_srcdir)/include/mesos/executor.hpp	\
 nodist_pkginclude_HEADERS = ../include/mesos/mesos.hpp mesos.pb.h
 
 if OS_LINUX
-  libmesos_no_third_party_la_SOURCES += slave/cgroups_isolator.cpp
-  libmesos_no_third_party_la_SOURCES += linux/cgroups.cpp
-  libmesos_no_third_party_la_SOURCES += linux/fs.cpp
+  libmesos_no_3rdparty_la_SOURCES += slave/cgroups_isolator.cpp
+  libmesos_no_3rdparty_la_SOURCES += linux/cgroups.cpp
+  libmesos_no_3rdparty_la_SOURCES += linux/fs.cpp
 else
   EXTRA_DIST += slave/cgroups_isolator.cpp
   EXTRA_DIST += linux/cgroups.cpp
   EXTRA_DIST += linux/fs.cpp
 endif
 
-libmesos_no_third_party_la_SOURCES += common/attributes.hpp		\
+libmesos_no_3rdparty_la_SOURCES += common/attributes.hpp		\
 	common/build.hpp common/date_utils.hpp common/factory.hpp	\
 	common/protobuf_utils.hpp					\
 	common/lock.hpp common/resources.hpp common/process_utils.hpp	\
@@ -244,9 +244,9 @@ libmesos_no_third_party_la_SOURCES += common/attributes.hpp		\
 	zookeeper/group.hpp zookeeper/watcher.hpp			\
 	zookeeper/zookeeper.hpp zookeeper/url.hpp
 
-libmesos_no_third_party_la_CPPFLAGS = $(MESOS_CPPFLAGS)
+libmesos_no_3rdparty_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 
-libmesos_no_third_party_la_LIBADD = # Initialized to enable using +=.
+libmesos_no_3rdparty_la_LIBADD = # Initialized to enable using +=.
 
 # Convenience library that *always* gets rebuilt to ensure accurate info.
 noinst_LTLIBRARIES += libbuild.la
@@ -265,7 +265,7 @@ BUILD_FLAGS = $(echo $(MESOS_CPPFLAGS) $(CPPFLAGS) | sed 's/\"/\\\"/g') \
 
 libbuild_la_CPPFLAGS += -DBUILD_FLAGS="\"$$BUILD_FLAGS\""
 
-libmesos_no_third_party_la_LIBADD += libbuild.la
+libmesos_no_3rdparty_la_LIBADD += libbuild.la
 
 
 # Convenience library for building the replicated log in order to
@@ -277,7 +277,7 @@ liblog_la_SOURCES += log/coordinator.hpp log/replica.hpp log/log.hpp	\
 nodist_liblog_la_SOURCES = $(LOG_PROTOS)
 liblog_la_CPPFLAGS = -I../$(LEVELDB)/include $(MESOS_CPPFLAGS)
 
-libmesos_no_third_party_la_LIBADD += liblog.la
+libmesos_no_3rdparty_la_LIBADD += liblog.la
 
 
 # Convenience library for building "state" abstraction in order to
@@ -295,7 +295,7 @@ libstate_la_SOURCES += 			\
 nodist_libstate_la_SOURCES = $(STATE_PROTOS)
 libstate_la_CPPFLAGS = -I../$(LEVELDB)/include $(MESOS_CPPFLAGS)
 
-libmesos_no_third_party_la_LIBADD += libstate.la
+libmesos_no_3rdparty_la_LIBADD += libstate.la
 
 # The final result!
 lib_LTLIBRARIES += libmesos.la
@@ -309,7 +309,7 @@ libmesos_la_LDFLAGS = -release $(PACKAGE_VERSION) -shared
 libmesos_la_LIBTOOLFLAGS = --tag=CXX
 
 # Add the convenience library.
-libmesos_la_LIBADD = libmesos_no_third_party.la
+libmesos_la_LIBADD = libmesos_no_3rdparty.la
 
 # For non-convenience libraries we need to link them in to make the shared
 # library each time. (Currently, we don't support platforms where this is not
@@ -319,7 +319,7 @@ libmesos_la_LIBADD += ../$(GLOG)/libglog.la
 
 # We need to directly include the leveldb library in order to avoid
 # the installed libmesos.la file to include leveldb in
-# 'dependency_libs' (via '-L../third_party/leveldb -lleveldb').
+# 'dependency_libs' (via '-L../3rdparty/leveldb -lleveldb').
 libmesos_la_LIBADD += ../$(LEVELDB)/libleveldb.a
 
 if WITH_INCLUDED_ZOOKEEPER
@@ -395,7 +395,7 @@ nobase_dist_webui_DATA +=						\
 # Need to distribute/install webui images.
 nobase_dist_webui_DATA += webui/master/static/loading.gif
 
-# Need to distribute/install third_party javascript.
+# Need to distribute/install third-party javascript.
 nobase_dist_webui_DATA +=						\
   webui/master/static/angular-1.0.0rc8.js				\
   webui/master/static/angular-1.0.0rc8.min.js				\
@@ -520,7 +520,7 @@ if HAS_JAVA
 # Protocol buffers JAR.
 PROTOBUF_JAR = ../protobuf-$(PROTOBUF_VERSION).jar
 
-# TODO(charles): Move into third_party/Makefile.am.
+# TODO(charles): Move into 3rdparty/Makefile.am.
 $(PROTOBUF_JAR): # TODO(charles): Specify dependencies for the jar.
 	@echo "Building protobuf-$(PROTOBUF_VERSION).jar ..."
 	$(MKDIR_P) ../$(PROTOBUF)/java/src/main/java
@@ -591,7 +591,7 @@ libjava_la_DEPENDENCIES = $(MESOS_PROTO)
 
 libjava_la_LIBADD = $(JAVA_LDFLAGS)
 
-# We don't add libjava.la to libmesos_no_third_party.la so we don't
+# We don't add libjava.la to libmesos_no_3rdparty.la so we don't
 # include the JNI bindings in the Python egg (but we might want to
 # reconsider this in the future). We also need to add the JAVA_LDFLAGS
 # to libmesos.la so on Linux we set the rpath for libmesos.so.
@@ -700,8 +700,8 @@ $(PROTOBUF_EGG):
 
 CLEANFILES += $(PROTOBUF_EGG)
 
-# This builds a Python egg against libmesos_no_third_party.a that is
-# self-contained. It currently depends on the libraries in third_party
+# This builds a Python egg against libmesos_no_3rdparty.a that is
+# self-contained. It currently depends on the libraries in 3rdparty
 # being built as .a's. (If this is changed, the setup.py will need to
 # be edited).
 
@@ -718,7 +718,7 @@ CLEANFILES += $(PROTOBUF_EGG)
 MESOS_EGG = python/dist/mesos-$(PACKAGE_VERSION)$(PYTHON_EGG_POSTFIX).egg
 
 $(MESOS_EGG): python/setup.py $(srcdir)/python/src/mesos.py	\
-              $(PYTHON_PROTOS) libmesos_no_third_party.la	\
+              $(PYTHON_PROTOS) libmesos_no_3rdparty.la	\
               $(PROTOBUF_EGG)
 	@echo "Building Mesos Python egg ..."
 	@if test "$(top_srcdir)" != "$(top_builddir)"; then \
@@ -823,7 +823,7 @@ mesos_tests_CPPFLAGS += -DBUILD_DIR=\"$(abs_top_builddir)\"
 mesos_tests_CPPFLAGS += -I../$(GTEST)/include
 mesos_tests_CPPFLAGS += -I../$(GMOCK)/include
 
-mesos_tests_LDADD = ../$(LIBPROCESS)/third_party/libgmock.la libmesos.la
+mesos_tests_LDADD = ../$(LIBPROCESS)/3rdparty/libgmock.la libmesos.la
 
 mesos_tests_DEPENDENCIES = # Initialized to allow += below.