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 2011/06/05 07:39:59 UTC

svn commit: r1131843 - in /incubator/mesos/trunk/src: Makefile.in configuration.cpp configuration.hpp params.hpp tests/external_test.cpp tests/external_test.hpp tests/main.cpp tests/test_configuration.cpp tests/testing_utils.cpp tests/testing_utils.hpp

Author: benh
Date: Sun Jun  5 05:39:58 2011
New Revision: 1131843

URL: http://svn.apache.org/viewvc?rev=1131843&view=rev
Log:
Various improvements on top of Ali's configuration framework:
- Configuring still works if MESOS_HOME and MESOS_CONF aren't given
- Renamed parse* methods to load*
- Made command line and environment var names get converted to lowercase
  for consistency
- Made Configuration throw exceptions when bad things happen so that we
  can report them to users / callers
- Added a testing util function for creating a work directory for a
  test, and started using it in config file test
- Fixed a bunch of C++ style / formatting throughout

Added:
    incubator/mesos/trunk/src/tests/testing_utils.cpp
Modified:
    incubator/mesos/trunk/src/Makefile.in
    incubator/mesos/trunk/src/configuration.cpp
    incubator/mesos/trunk/src/configuration.hpp
    incubator/mesos/trunk/src/params.hpp
    incubator/mesos/trunk/src/tests/external_test.cpp
    incubator/mesos/trunk/src/tests/external_test.hpp
    incubator/mesos/trunk/src/tests/main.cpp
    incubator/mesos/trunk/src/tests/test_configuration.cpp
    incubator/mesos/trunk/src/tests/testing_utils.hpp

Modified: incubator/mesos/trunk/src/Makefile.in
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/Makefile.in?rev=1131843&r1=1131842&r2=1131843&view=diff
==============================================================================
--- incubator/mesos/trunk/src/Makefile.in (original)
+++ incubator/mesos/trunk/src/Makefile.in Sun Jun  5 05:39:58 2011
@@ -93,7 +93,7 @@ LIBS += -lglog -lgtest -lprocess -lev -l
 
 NEXUS_EXES = nexus-master nexus-slave nexus-local nexus-launcher \
 	     test-framework test-executor cpp-test-framework cpp-test-executor \
-	     memhog memhog-executor scheduled-memhog
+	     memhog memhog-executor
 
 ifeq ($(OS_NAME),solaris)
   NEXUS_EXES += nexus-projd
@@ -108,13 +108,15 @@ NEXUS_LIB = libnexus++.a
 NEXUS_LIBS = $(SCHED_LIB) $(EXEC_LIB) $(NEXUS_LIB)
 
 MASTER_OBJ = master.o allocator_factory.o simple_allocator.o
-SLAVE_OBJ = slave.o launcher.o isolation_module.o \
+SLAVE_OBJ = slave.o launcher.o isolation_module_factory.o \
 	    process_based_isolation_module.o
-COMMON_OBJ = fatal.o hash_pid.o messages.o lock.o master_detector.o url_processor.o zookeeper.o
+COMMON_OBJ = fatal.o hash_pid.o messages.o lock.o master_detector.o \
+	     url_processor.o zookeeper.o configuration.o
 EXEC_LIB_OBJ = nexus_exec.o
 SCHED_LIB_OBJ = nexus_sched.o nexus_local.o params.o
 TEST_OBJ = tests/main.o tests/test_master.o tests/test_resources.o \
-	   tests/external_test.o tests/test_sample_frameworks.o
+	   tests/external_test.o tests/test_sample_frameworks.o \
+	   tests/testing_utils.o tests/test_configuration.o
 
 ifeq ($(OS_NAME),solaris)
   SLAVE_OBJ += solaris_project_isolation_module.o
@@ -224,10 +226,7 @@ memhog: memhog.cpp $(NEXUS_LIB) third_pa
 memhog-executor: memhog_executor.cpp $(NEXUS_LIB) third_party/libprocess/libprocess.a
 	$(CXX) $(CXXFLAGS) -o $@ $< -L. $(LDFLAGS) -lnexus++ $(LIBS) 
 
-scheduled-memhog: scheduled_memhog.cpp $(NEXUS_LIB) third_party/libprocess/libprocess.a
-	$(CXX) $(CXXFLAGS) -o $@ $< -L. $(LDFLAGS) -lnexus++ $(LIBS) 
-
-java: $(JAVA_LIB) swig/java/nexus.jar swig/java/TestFramework.class swig/java/TestExecutor.class
+java: $(JAVA_LIB) swig/java/nexus.jar swig/java/TestFramework.class swig/java/TestExecutor.class swig/java/TestExceptionFramework.class swig/java/TestExceptionExecutor.class
 
 python: $(PYTHON_LIB)
 
@@ -236,8 +235,8 @@ ruby: $(RUBY_LIB)
 swig/java/nexus.jar: $(JAVA_LIB)
 ifdef JAVA_HOME
 	$(JAVA_HOME)/bin/javac -sourcepath swig/java -d swig/java swig/java/nexus/*.java
-#	patch -N swig/java/nexus/nexusJNI.java < swig/java/nexusJNI.java.patch1 || echo -n
-#	patch swig/java/nexus/nexusJNI.java < swig/java/nexusJNI.java.patch2 || echo -n
+	patch -N swig/java/nexus/nexusJNI.java < swig/java/nexusJNI.java.patch1 || echo -n
+	patch swig/java/nexus/nexusJNI.java < swig/java/nexusJNI.java.patch2 || echo -n
 	$(JAVA_HOME)/bin/jar cf $@ -C swig/java nexus
 endif
 
@@ -259,6 +258,16 @@ ifdef JAVA_HOME
 	$(JAVA_HOME)/bin/javac -cp swig/java/nexus.jar -sourcepath swig/java -d swig/java swig/java/TestExecutor.java
 endif
 
+swig/java/TestExceptionFramework.class: $(JAVA_LIB) swig/java/nexus.jar swig/java/TestExceptionFramework.java
+ifdef JAVA_HOME
+	$(JAVA_HOME)/bin/javac -cp swig/java/nexus.jar -sourcepath swig/java -d swig/java swig/java/TestExceptionFramework.java
+endif
+
+swig/java/TestExceptionExecutor.class: $(JAVA_LIB) swig/java/nexus.jar swig/java/TestExceptionExecutor.java
+ifdef JAVA_HOME
+	$(JAVA_HOME)/bin/javac -cp swig/java/nexus.jar -sourcepath swig/java -d swig/java swig/java/TestExceptionExecutor.java
+endif
+
 $(PYTHON_LIB): swig/nexus.i $(NEXUS_LIB)
 ifdef PYTHON_HEADERS
 	$(SWIG) -c++ -python -threads -I../include -o swig/python/nexus_wrap.cpp -outdir swig/python swig/nexus.i

Modified: incubator/mesos/trunk/src/configuration.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/configuration.cpp?rev=1131843&r1=1131842&r2=1131843&view=diff
==============================================================================
--- incubator/mesos/trunk/src/configuration.cpp (original)
+++ incubator/mesos/trunk/src/configuration.cpp Sun Jun  5 05:39:58 2011
@@ -1,83 +1,74 @@
+#include <libgen.h>
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <iostream>
 
-#include "configuration.hpp"
+#include <boost/foreach.hpp>
 
+#include "configuration.hpp"
 #include "params.hpp"
-#include "boost/foreach.hpp"
 
-using std::cout;
-using std::endl;
+extern char** environ;   // libc's environment variable list; for some reason,
+                         // this is not in headers on all platforms
 
 using namespace nexus::internal;
 
-extern char** environ;
+
+const char* Configuration::DEFAULT_CONFIG_DIR = "conf";
+const char* Configuration::CONFIG_FILE_NAME = "mesos.conf";
+const char* Configuration::ENV_VAR_PREFIX = "MESOS_";
 
 
 Configuration::Configuration() 
 {
-  parseEnv();
-  string cnf;
-  const map<string,string> &map = params.getMap();
-  if (map.find("CONF") != map.end())
-    cnf = params["CONF"];
-  else 
-    cnf = getMesosHome() + "/" + DEFAULT_CONF_NAME;
-  parseConfig(cnf);
-}
-
-Configuration::Configuration(int argc, char **argv) 
-{
-  parseEnv();
-  parseCmdline(argc, argv);
-  string cnf;
-  const map<string,string> &map = params.getMap();
-  if (map.find("CONF") != map.end())
-    cnf = params["CONF"];
-  else 
-    cnf = getMesosHome() + "/" + DEFAULT_CONF_NAME;
-  parseConfig(cnf);
-}
-
-Configuration::Configuration(const map<string,string> &_params) 
-{
-  parseEnv();
-  params.parseMap(_params);
-  string cnf;
-  const map<string,string> &map = params.getMap();
-  if (map.find("CONF") != map.end())
-    cnf = params["CONF"];
-  else 
-    cnf = getMesosHome() + "/" + DEFAULT_CONF_NAME;
-  parseConfig(cnf);
-}
-
-string Configuration::getMesosHome() 
-{
-  string mesosHome;
-  if (params.getMap().find("HOME") == params.getMap().end()) {
-    mesosHome = DEFAULT_HOME;
-    LOG(WARNING) << "MESOS_HOME environment variable not set. Using default " 
-                 << mesosHome;
-  } else {
-    mesosHome = params["HOME"];
-  }
-  return mesosHome;
+  loadEnv();
+  loadConfigFileIfGiven();
+}
+
+
+Configuration::Configuration(int argc,
+                             char** argv,
+                             bool inferMesosHomeFromArg0) 
+{
+  loadEnv();
+  loadCommandLine(argc, argv, inferMesosHomeFromArg0);
+  loadConfigFileIfGiven();
+}
+
+
+Configuration::Configuration(const map<string, string>& _params) 
+{
+  loadEnv();
+  params.loadMap(_params);
+  loadConfigFileIfGiven();
+}
+
+
+void Configuration::loadConfigFileIfGiven() {
+  string confDir = "";
+  if (params.contains("conf"))
+    confDir = params["conf"];
+  else if (params.contains("home")) // find conf dir relative to MESOS_HOME
+    confDir = params["home"] + "/" + DEFAULT_CONFIG_DIR;
+  if (confDir != "")
+    loadConfigFile(confDir + "/" + CONFIG_FILE_NAME);
 }
 
-void Configuration::parseEnv()
+
+void Configuration::loadEnv()
 {
   int i = 0;
-  while(environ[i] != NULL) {
+  while (environ[i] != NULL) {
     string line = environ[i];
-    if (line.find(DEFAULT_PREFIX) == 0) {
+    if (line.find(ENV_VAR_PREFIX) == 0) {
       string key, val;
-      string::size_type eq = line.find_first_of("=");
-      if (eq == string::npos)  
-        continue; // ignore problematic strings
-      key = line.substr(sizeof(DEFAULT_PREFIX)-1, eq - (sizeof(DEFAULT_PREFIX)-1));
+      size_t eq = line.find_first_of("=");
+      if (eq == string::npos) 
+        continue; // ignore malformed lines (they shouldn't occur in environ!)
+      key = line.substr(strlen(ENV_VAR_PREFIX), eq - strlen(ENV_VAR_PREFIX));
+      std::transform(key.begin(), key.end(), key.begin(), ::tolower);
       val = line.substr(eq + 1);
       params[key] = val;
     }
@@ -85,42 +76,51 @@ void Configuration::parseEnv()
   }
 }
 
-void Configuration::parseMap(const map<string, string> &map)
-{
-  params.parseMap(map);
-}
 
-void Configuration::parseCmdline(int argc, char **argv)
-{
-  vector<string> args;
-  map<string,string> store;
+void Configuration::loadCommandLine(int argc,
+                                    char** argv,
+                                    bool inferMesosHomeFromArg0)
+{
+  // Set home based on argument 0 if asked to do so
+  if (inferMesosHomeFromArg0) {
+    char buf[4096];
+    realpath(dirname(argv[0]), buf);
+    params["home"] = buf;
+  }
 
-  for (int i=1; i < argc; i++)
-    args.push_back(argv[i]);
+  // Convert args 1 and above to STL strings
+  vector<string> args;
+  for (int i=1; i < argc; i++) {
+    args.push_back(string(argv[i]));
+  }
 
-  argc = args.size(); // argc -= 1
-    
-  for (int i=0; i < argc; i++) {
+  for (int i = 0; i < args.size(); i++) {
     string key, val;
     bool set = false;
-    if (args[i].find("--", 0) == 0) {  // handles --blah=25 and --blah
-      string::size_type eq = args[i].find_first_of("=");
+    if (args[i].find("--", 0) == 0) {
+      // handle --blah=25 and --blah
+      size_t eq = args[i].find_first_of("=");
       if (eq == string::npos) {        
         key = args[i].substr(2);
+        std::transform(key.begin(), key.end(), key.begin(), ::tolower);
         val = "1";
         set = true;
-      } else {                         
+      } else {
         key = args[i].substr(2, eq-2);
         val = args[i].substr(eq+1);
         set = true;
       } 
-    } else if (args[i].find_first_of("-", 0) == 0) { // handles -blah 25 and -blah
-      if ((i+1 >= argc) || (i+1 < argc && args[i+1].find_first_of("-",0) == 0)) {
+    } else if (args[i].find_first_of("-", 0) == 0) {
+      // handle -blah 25 and -blah
+      if ((i+1 >= args.size()) ||
+          (i+1 < args.size() && args[i+1].find_first_of("-", 0) == 0)) {
         key = args[i].substr(1);
+        std::transform(key.begin(), key.end(), key.begin(), ::tolower);
         val = "1";
         set = true;
-      } else if (i+1 < argc && args[i+1].find_first_of("-",0) != 0) {
+      } else if (i+1 < args.size() && args[i+1].find_first_of("-", 0) != 0) {
         key = args[i].substr(1);
+        std::transform(key.begin(), key.end(), key.begin(), ::tolower);
         val = args[i+1];
         set = true;
         i++;  // we've consumed next parameter as "value"-parameter
@@ -132,29 +132,28 @@ void Configuration::parseCmdline(int arg
   }
 }
 
-int Configuration::parseConfig(const string &fname) {
+
+void Configuration::loadConfigFile(const string& fname) {
   ifstream cfg(fname.c_str(), std::ios::in);
   if (!cfg.is_open()) {
-    LOG(ERROR) << "Couldn't read Mesos configuration file from: " 
-               << fname;
-    return -1;
+    string message = "Couldn't read Mesos config file: " + fname;
+    throw new ConfigurationException(message.c_str());
   }
 
   string buf, line;
 
   while (!cfg.eof()) {
     getline(cfg, line);
-    string::size_type beg = line.find_first_of("#"); // strip comments
+    size_t beg = line.find_first_of("#"); // strip comments
     beg = line.find_last_not_of("#\t \n\r", beg) + 1; // strip trailing ws
     buf += line.substr(0, beg) + "\n";
   }
   cfg.close();
-  params.parseString(buf);
-  return 0;
+  params.loadString(buf);
 }
 
-Params &Configuration::getParams() 
+
+Params& Configuration::getParams() 
 {
   return params;
 }
-

Modified: incubator/mesos/trunk/src/configuration.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/configuration.hpp?rev=1131843&r1=1131842&r2=1131843&view=diff
==============================================================================
--- incubator/mesos/trunk/src/configuration.hpp (original)
+++ incubator/mesos/trunk/src/configuration.hpp Sun Jun  5 05:39:58 2011
@@ -15,75 +15,82 @@ using std::endl;
 using std::ifstream;
 using std::map;
 
-#define DEFAULT_HOME "./"
-#define DEFAULT_CONF_NAME "mesos.conf"
-#define DEFAULT_PREFIX "MESOS_"
-
 namespace nexus { namespace internal {
     
+
+/**
+ * Exception type thrown by Configuration.
+ */
+struct ConfigurationException : std::exception
+{
+  const char* message;
+  ConfigurationException(const char* msg): message(msg) {}
+  const char* what() const throw () { return message; }
+};
+
+
 /** 
- * Class that populates a Params object, which can be retrieved with getParams().
+ * This class populates a Params object, which can be retrieved with
+ * getParams(), by reading variables from the command line, a config file
+ * or the environment.
+ *
  * It currently supports 3 input types:
  * (i) Environment variables. It adds all variables starting with MESOS_.
- * (ii) Command line variables. It supports "--key=val" "-key val" "-opt" "--opt"
+ * (ii) Command line variables. Supports "--key=val" "-key val" "-opt" "--opt"
  * (iii) Config file. It ignores comments "#". It finds the file using
- * MESOS_CONF or via command line --CONF=file. Otherwise, it looks for
- * "mesos.conf" in MESOS_HOME or --HOME=dir. 
- 
+ * MESOS_CONF or via command line --conf=file. Otherwise, it looks for
+ * "mesos.conf" in MESOS_HOME/conf.
  **/
-    
 class Configuration 
 {
 public:
+  static const char* DEFAULT_CONFIG_DIR;
+  static const char* CONFIG_FILE_NAME;
+  static const char* ENV_VAR_PREFIX;
+
+private:
+  Params params;
+
+public:
   /** 
-   * Constructor that populates Params from environment and config file only.
+   * Constructor that populates Params from environment and any config file
+   * located through the environment (through MESOS_HOME or MESOS_CONF).
    **/
   Configuration();
 
   /** 
    * Constructor that populates Params from environment, command line,
-   * and config file only.
+   * and any config file specified through these.
    *
    * @param argc number of paramters in argv
    * @param argv array of c-strings from the command line
+   * @param inferMesosHomeFromArg0 whether to set mesos home to directory
+   *                               containing argv[0] (the program being run)
    **/
-  Configuration(int argc, char **argv);
+  Configuration(int argc, char** argv, bool inferMesosHomeFromArg0);
   
   /** 
    * Constructor that populates Params from environment, a map,
-   * and config file only.
+   * and any config file specified through these.
    *
    * @param argc number of paramters in argv
    * @param argv array of c-strings from the command line
    **/
-  Configuration(const map<string,string> &_params);
+  Configuration(const map<string, string>& _params);
 
   /**
-   * Returns a Params that is populated through parse* methods.
+   * Returns the Params object parsed by this Configuration.
    * @return Params populated params object
    **/
-  Params &getParams();
+  Params& getParams();
 
 private:
   /**
-   * Returns the current Mesos home directory
-   *
-   * @return Home directory is extracted from Params. If it doesn't exist
-   * it return the current directory as a default. 
-   **/
-  string getMesosHome();
-
-  /**
    * Parses the environment variables and populates a Params.
    * It picks all environment variables that start with MESOS_.
    * The environment variable MESOS_HOME=/dir would lead to key=HOME val=/dir
    **/
-  void parseEnv();
-
-  /**
-   * Populates its internal Params with key value params from a map.
-   **/
-  void parseMap(const map<string, string> &map);
+  void loadEnv();
 
   /**
    * Populates its internal Params with key/value params from command line.
@@ -93,19 +100,24 @@ private:
    *
    * @param argc is the number of parameters in argv
    * @param argv is an array of c-strings containing params
+   * @param inferMesosHomeFromArg0 whether to set mesos home to directory
+   *                               containing argv[0] (the program being run)
    **/
-  void parseCmdline(int argc, char **argv);
+  void loadCommandLine(int argc, char** argv, bool inferMesosHomeFromArg0);
 
   /**
    * Populates its internal Params with key/value params from a config file.
-   * It ignores comments starting with "#"
+   * The config file should contain key=value pairs, one per line.
+   * Comments, which should start with #, are ignored.
    *
    * @param fname is the name of the config file to open
    **/
-  int parseConfig(const string &fname);
+  void loadConfigFile(const string& fname);
 
-  string mesosHome;
-  Params params;
+  /**
+   * Load the config file set through the command line or environment, if any.
+   */
+  void loadConfigFileIfGiven();
 };
 
 } }   // end nexus :: internal namespace

Modified: incubator/mesos/trunk/src/params.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/params.hpp?rev=1131843&r1=1131842&r2=1131843&view=diff
==============================================================================
--- incubator/mesos/trunk/src/params.hpp (original)
+++ incubator/mesos/trunk/src/params.hpp Sun Jun  5 05:39:58 2011
@@ -27,7 +27,7 @@ using boost::lexical_cast;
 struct ParseException : std::exception
 {
   const char* message;
-  ParseException(const char *msg): message(msg) {}
+  ParseException(const char* msg): message(msg) {}
   const char* what() const throw () { return message; }
 };
 
@@ -47,17 +47,24 @@ public:
 
   Params(const string& str)
   {
-    parseString(str);
+    loadString(str);
   }
 
-  void parseMap(const map<string, string>& params_)
+  /**
+   * Load key-value pairs from a map into this Params object.
+   */
+  void loadMap(const map<string, string>& params_)
   {
-    foreachpair(const string &k, const string &v, params_) {
+    foreachpair(const string& k, const string& v, params_) {
       params[k] = v;
     }
   }
 
-  void parseString(const string &str)
+  /**
+   * Load key-value pairs from a string into this Params object.
+   * The string should contain pairs of the form key=value, one per line.
+   */
+  void loadString(const string& str)
   {
     vector<string> lines;
     split(str, "\n\r", lines);
@@ -136,6 +143,11 @@ public:
     return params;
   }
 
+  bool contains(const string& key) const
+  {
+    return params.find(key) != params.end();
+  }
+
 private:
   void split(const string& str, const string& delims, vector<string>& tokens)
   {

Modified: incubator/mesos/trunk/src/tests/external_test.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external_test.cpp?rev=1131843&r1=1131842&r2=1131843&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/external_test.cpp (original)
+++ incubator/mesos/trunk/src/tests/external_test.cpp Sun Jun  5 05:39:58 2011
@@ -1,6 +1,5 @@
 #include <gtest/gtest.h>
 
-#include <ctype.h>
 #include <stdlib.h>
 
 #include <string>
@@ -12,21 +11,7 @@
 #include "testing_utils.hpp"
 
 using std::string;
-
-namespace {
-
-// Check that a test name contains only letters, numbers and underscores, to
-// prevent messing with directories outside test_output in runExternalTest.
-bool isValidTestName(const char* name) {
-  for (const char* p = name; *p != 0; p++) {
-    if (!isalnum(*p) && *p != '_') {
-      return false;
-    }
-  }
-  return true;
-}
-
-}
+using namespace nexus::internal::test;
 
 
 /**
@@ -36,22 +21,14 @@ bool isValidTestName(const char* name) {
  * piping its output to files called stdout and stderr, and the test
  * passes if the script returns 0.
  */
-void nexus::test::runExternalTest(const char* testCase, const char* testName)
+void nexus::internal::test::runExternalTest(const char* testCase,
+                                            const char* testName)
 {
-  // Check that the test name is valid
-  if (!isValidTestName(testCase) || !isValidTestName(testName)) {
-    FAIL() << "Invalid test name for external test (name should " 
-           << "only contain alphanumeric and underscore characters)";
-  }
+  // Create and go into the test's work directory
+  enterTestDirectory(testCase, testName);
   // Figure out the absolute path to the test script
-  string script = MESOS_HOME + "/tests/external/" + testCase
+  string script = mesosHome + "/tests/external/" + testCase
                              + "/" + testName + ".sh";
-  // Make the work directory for this test
-  string workDir = MESOS_HOME + "/test_output/" + testCase + "/" + testName;
-  string command = "rm -fr '" + workDir + "'";
-  ASSERT_EQ(0, system(command.c_str())) << "Command failed: " << command;
-  command = "mkdir -p '" + workDir + "'";
-  ASSERT_EQ(0, system(command.c_str())) << "Command failed: " << command;
   // Fork a process to change directory and run the test
   pid_t pid;
   if ((pid = fork()) == -1) {
@@ -63,14 +40,13 @@ void nexus::test::runExternalTest(const 
     wait(&exitCode);
     ASSERT_EQ(0, exitCode) << "External test " << testName << " failed";
   } else {
-    // In child process. Go into to the work directory, redirect IO to files,
+    // In child process. Redirect standard output and error to files,
     // set MESOS_HOME environment variable, and exec the test script.
-    chdir(workDir.c_str());
     if (freopen("stdout", "w", stdout) == NULL)
       fatalerror("freopen failed");
     if (freopen("stderr", "w", stderr) == NULL)
       fatalerror("freopen failed");
-    setenv("MESOS_HOME", MESOS_HOME.c_str(), 1);
+    setenv("MESOS_HOME", mesosHome.c_str(), 1);
     execl(script.c_str(), script.c_str(), (char*) NULL);
     // If we get here, execl failed; report the error
     fatalerror("Could not execute %s", script.c_str());

Modified: incubator/mesos/trunk/src/tests/external_test.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external_test.hpp?rev=1131843&r1=1131842&r2=1131843&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/external_test.hpp (original)
+++ incubator/mesos/trunk/src/tests/external_test.hpp Sun Jun  5 05:39:58 2011
@@ -12,10 +12,10 @@
  */
 #define TEST_EXTERNAL(testCase, testName) \
   TEST(testCase, testName) { \
-    nexus::test::runExternalTest(#testCase, #testName); \
+    nexus::internal::test::runExternalTest(#testCase, #testName); \
   }
 
-namespace nexus { namespace test {
+namespace nexus { namespace internal { namespace test {
 
 /**
  * Function called by TEST_EXTERNAL to execute external tests. See
@@ -23,6 +23,6 @@ namespace nexus { namespace test {
  */
 void runExternalTest(const char* testCase, const char* testName);
 
-}} /* namespace nexus::test */
+}}} /* namespace nexus::internal::test */
 
 #endif /* __EXTERNAL_TEST_HPP__ */

Modified: incubator/mesos/trunk/src/tests/main.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/main.cpp?rev=1131843&r1=1131842&r2=1131843&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/main.cpp (original)
+++ incubator/mesos/trunk/src/tests/main.cpp Sun Jun  5 05:39:58 2011
@@ -7,17 +7,17 @@
 #include <iostream>
 #include <string>
 
-using std::string;
+#include "testing_utils.hpp"
 
-string MESOS_HOME;
+using namespace nexus::internal::test;
 
 
 int main(int argc, char **argv) {
   // Get absolute path to Mesos home direcotry (really src right now)
   char buf[4096];
   realpath(dirname(argv[0]), buf);
-  MESOS_HOME = buf;
-  std::cout << "Mesos home is " << MESOS_HOME << std::endl;
+  mesosHome = buf;
+  std::cout << "Mesos home is " << mesosHome << std::endl;
 
   google::InitGoogleLogging("alltests");
   testing::InitGoogleTest(&argc, argv);

Modified: incubator/mesos/trunk/src/tests/test_configuration.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/test_configuration.cpp?rev=1131843&r1=1131842&r2=1131843&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/test_configuration.cpp (original)
+++ incubator/mesos/trunk/src/tests/test_configuration.cpp Sun Jun  5 05:39:58 2011
@@ -5,6 +5,7 @@
 #include <boost/lexical_cast.hpp>
 
 #include "configuration.hpp"
+#include "testing_utils.hpp"
 
 using std::ofstream;
 using std::string;
@@ -15,29 +16,31 @@ using boost::lexical_cast;
 
 using namespace nexus;
 using namespace nexus::internal;
+using namespace nexus::internal::test;
 
-TEST(ConfigurationTest, EnvironTest)
-{
 
-  setenv("MESOS_TEST","working", true);
+TEST(ConfigurationTest, Environment)
+{
+  setenv("MESOS_TEST", "working", true);
   Configuration c1;
   unsetenv("MESOS_TEST");
 
-  EXPECT_TRUE(c1.getParams()["TEST"] == "working");
+  EXPECT_TRUE(c1.getParams()["test"] == "working");
 }
 
-TEST(ConfigurationTest, CmdTest)
+
+TEST(ConfigurationTest, CommandLine)
 {
-  #define ARGC 6
-  char *argv[ARGC];
-  argv[0] = (char *) "./filename";
-  argv[1] = (char *) "--test1=text1";
-  argv[2] = (char *) "--test2";
-  argv[3] = (char *) "-test3";
-  argv[4] = (char *) "text2";
-  argv[5] = (char *) "-test4";
+  const int ARGC = 6;
+  char* argv[ARGC];
+  argv[0] = (char*) "./filename";
+  argv[1] = (char*) "--test1=text1";
+  argv[2] = (char*) "--test2";
+  argv[3] = (char*) "-test3";
+  argv[4] = (char*) "text2";
+  argv[5] = (char*) "-test4";
 
-  Configuration c1(ARGC, argv);
+  Configuration c1(ARGC, argv, false);
 
   EXPECT_TRUE(c1.getParams()["test1"] == "text1");
   EXPECT_TRUE(c1.getParams()["test2"] == "1");
@@ -45,33 +48,37 @@ TEST(ConfigurationTest, CmdTest)
   EXPECT_TRUE(c1.getParams()["test4"] == "1");
 }
 
-// The below test creates files. We have to enable tests to do that safely.
-/*
-TEST(ConfigurationTest, ConfTest)
+
+TEST(ConfigurationTest, ConfigFile)
 {
-  ofstream file("mesos.conf");
-  file << "TEST1=coffee # beans are tasty\n";
+  enterTestDirectory("ConfigurationTest", "ConfigFile");
+
+  if (mkdir("conf", 0755) != 0)
+    FAIL() << "Failed to create directory conf";
+  ofstream file("conf/mesos.conf");
+  file << "test1=coffee # beans are tasty\n";
   file << "# just a comment\n";
-  file << "TEST2=tea\n";
+  file << "test2=tea\n";
   file.close();
 
-  setenv("MESOS_HOME", "./", 1);
+  setenv("MESOS_HOME", ".", 1);
   Configuration c1;
   unsetenv("MESOS_HOME");
 
-  EXPECT_TRUE(c1.getParams()["TEST1"] == "coffee");
-  EXPECT_TRUE(c1.getParams()["TEST2"] == "tea");
+  EXPECT_TRUE(c1.getParams()["test1"] == "coffee");
+  EXPECT_TRUE(c1.getParams()["test2"] == "tea");
 
-  ofstream file2("misus.conf");
-  file2 << "TEST3=shake # sugar bomb\n";
+  if (mkdir("conf2", 0755) != 0)
+    FAIL() << "Failed to create directory conf2";
+  ofstream file2("conf2/mesos.conf");
+  file2 << "test3=shake # sugar bomb\n";
   file2 << "# just a comment\n";
-  file2 << "TEST4=milk\n";
+  file2 << "test4=milk\n";
   file2.close();
-  setenv("MESOS_CONF", "misus.conf", 1);
+  setenv("MESOS_CONF", "conf2", 1);
   Configuration c2;
   unsetenv("MESOS_CONF");
 
-  EXPECT_TRUE(c2.getParams()["TEST3"] == "shake");
-  EXPECT_TRUE(c2.getParams()["TEST4"] == "milk");
+  EXPECT_TRUE(c2.getParams()["test3"] == "shake");
+  EXPECT_TRUE(c2.getParams()["test4"] == "milk");
 }
-*/

Added: incubator/mesos/trunk/src/tests/testing_utils.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/testing_utils.cpp?rev=1131843&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/testing_utils.cpp (added)
+++ incubator/mesos/trunk/src/tests/testing_utils.cpp Sun Jun  5 05:39:58 2011
@@ -0,0 +1,53 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include "testing_utils.hpp"
+
+using std::string;
+
+using namespace nexus::internal;
+
+
+string test::mesosHome;
+
+
+namespace {
+
+// Check that a test name contains only letters, numbers and underscores, to
+// prevent messing with directories outside test_output in runExternalTest.
+bool isValidTestName(const char* name) {
+  for (const char* p = name; *p != 0; p++) {
+    if (!isalnum(*p) && *p != '_') {
+      return false;
+    }
+  }
+  return true;
+}
+
+} // namespace
+
+
+/**
+ * Create and clean up the work directory for a given test, and cd into it,
+ * given the test's test case name and test name.
+ * Test directories are placed in <mesosHome>/test_output/<testCase>/<testName>.
+ */
+void test::enterTestDirectory(const char* testCase, const char* testName)
+{
+  // Check that the test name is valid
+  if (!isValidTestName(testCase) || !isValidTestName(testName)) {
+    FAIL() << "Invalid test name for external test (name should " 
+           << "only contain alphanumeric and underscore characters)";
+  }
+  // Make the work directory for this test
+  string workDir = mesosHome + "/test_output/" + testCase + "/" + testName;
+  string command = "rm -fr '" + workDir + "'";
+  ASSERT_EQ(0, system(command.c_str())) << "Command failed: " << command;
+  command = "mkdir -p '" + workDir + "'";
+  ASSERT_EQ(0, system(command.c_str())) << "Command failed: " << command;
+  // Change dir into it
+  chdir(workDir.c_str());
+}

Modified: incubator/mesos/trunk/src/tests/testing_utils.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/testing_utils.hpp?rev=1131843&r1=1131842&r2=1131843&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/testing_utils.hpp (original)
+++ incubator/mesos/trunk/src/tests/testing_utils.hpp Sun Jun  5 05:39:58 2011
@@ -3,9 +3,24 @@
 
 #include <string>
 
-// The location where Mesos is installed, used by tests to locate various
-// frameworks and binaries. For now it points to the src directory, until
-// we clean up our directory structure a little. Initialized in main.cpp.
-extern std::string MESOS_HOME;
+namespace nexus { namespace internal { namespace test {
+
+/**
+ * The location where Mesos is installed, used by tests to locate various
+ * frameworks and binaries. For now it points to the src directory, until
+ * we clean up our directory structure a little. Initialized in main.cpp.
+ */
+extern std::string mesosHome;
+
+
+/**
+ * Create and clean up the work directory for a given test, and cd into it,
+ * given the test's test case name and test name.
+ * Test directories are placed in <mesosHome>/test_output/<testCase>/<testName>.
+ */
+void enterTestDirectory(const char* testCase, const char* testName);
+
+
+}}} // namespace nexus::internal::test
 
 #endif /* __TESTING_UTILS_HPP__ */