Added CONFIG environment variable to build and test scripts, fixed some bugs
diff --git a/tools/run_tests/build_node.sh b/tools/run_tests/build_node.sh
index c3e88c5..c85ecf1 100755
--- a/tools/run_tests/build_node.sh
+++ b/tools/run_tests/build_node.sh
@@ -36,12 +36,8 @@
 # change to grpc repo root
 cd $(dirname $0)/../..
 
-# tells npm install to look for files in that directory
-export GRPC_ROOT=`pwd`
-# tells npm install the subdirectory with library files
-export GRPC_LIB_SUBDIR=libs/$CONFIG
-# tells npm install not to use default locations
-export GRPC_NO_INSTALL=yes
+export CXXFLAGS=-I`pwd`/include
+export LDFLAGS=-L`pwd`/libs/$CONFIG
 
 cd src/node
 
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index ad65da5..26caf03 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -136,7 +136,7 @@
 class JobSpec(object):
   """Specifies what to run for a job."""
 
-  def __init__(self, cmdline, shortname=None, environ={}, hash_targets=[]):
+  def __init__(self, cmdline, shortname=None, environ=None, hash_targets=None):
     """
     Arguments:
       cmdline: a list of arguments to pass as the command line
@@ -144,6 +144,10 @@
       hash_targets: which files to include in the hash representing the jobs version
                     (or empty, indicating the job should not be hashed)
     """
+    if environ is None:
+      environ = {}
+    if hash_targets is None:
+      hash_targets = []
     self.cmdline = cmdline
     self.environ = environ
     self.shortname = cmdline[0] if shortname is None else shortname
diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh
index ccf1b9d..3a82c04 100755
--- a/tools/run_tests/run_node.sh
+++ b/tools/run_tests/run_node.sh
@@ -30,9 +30,13 @@
 
 set -ex
 
+CONFIG=${CONFIG:-opt}
+
 # change to grpc repo root
 cd $(dirname $0)/../..
 
 root=`pwd`
 
+export LD_LIBRARY_PATH=$root/libs/$CONFIG
+
 $root/src/node/node_modules/mocha/bin/mocha $root/src/node/test
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index e1e4a4b..63bd0b7 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -51,11 +51,14 @@
 # SimpleConfig: just compile with CONFIG=config, and run the binary to test
 class SimpleConfig(object):
 
-  def __init__(self, config, environ={}):
+  def __init__(self, config, environ=None):
+    if environ is None:
+      environ = {}
     self.build_config = config
     self.maxjobs = 2 * multiprocessing.cpu_count()
     self.allow_hashing = (config != 'gcov')
     self.environ = environ
+    self.environ['CONFIG'] = config
 
   def job_spec(self, binary, hash_targets):
     return jobset.JobSpec(cmdline=[binary],
@@ -67,7 +70,9 @@
 # ValgrindConfig: compile with some CONFIG=config, but use valgrind to run
 class ValgrindConfig(object):
 
-  def __init__(self, config, tool, args=[]):
+  def __init__(self, config, tool, args=None):
+    if args is None:
+      args = []
     self.build_config = config
     self.tool = tool
     self.args = args
@@ -104,6 +109,12 @@
   def build_steps(self):
     return []
 
+  def supports_multi_config(self):
+    return True
+
+  def __str__(self):
+    return self.make_target
+
 
 class NodeLanguage(object):
 
@@ -116,6 +127,12 @@
   def build_steps(self):
     return [['tools/run_tests/build_node.sh']]
 
+  def supports_multi_config(self):
+    return False
+
+  def __str__(self):
+    return 'node'
+
 
 class PhpLanguage(object):
 
@@ -128,6 +145,12 @@
   def build_steps(self):
     return [['tools/run_tests/build_php.sh']]
 
+  def supports_multi_config(self):
+    return False
+
+  def __str__(self):
+    return 'php'
+
 
 class PythonLanguage(object):
 
@@ -140,6 +163,12 @@
   def build_steps(self):
     return [['tools/run_tests/build_python.sh']]
 
+  def supports_multi_config(self):
+    return False
+
+  def __str__(self):
+    return 'python'
+
 class RubyLanguage(object):
 
   def test_specs(self, config, travis):
@@ -151,6 +180,12 @@
   def build_steps(self):
     return [['tools/run_tests/build_ruby.sh']]
 
+  def supports_multi_config(self):
+    return False
+
+  def __str__(self):
+    return 'ruby'
+
 class CSharpLanguage(object):
 
   def test_specs(self, config, travis):
@@ -162,6 +197,12 @@
   def build_steps(self):
     return [['tools/run_tests/build_csharp.sh']]
 
+  def supports_multi_config(self):
+    return False
+
+  def __str__(self):
+    return 'csharp'
+
 # different configurations we can run under
 _CONFIGS = {
     'dbg': SimpleConfig('dbg'),
@@ -226,6 +267,13 @@
 
 make_targets = []
 languages = set(_LANGUAGES[l] for l in args.language)
+
+if len(build_configs) > 1:
+  for language in languages:
+    if not language.supports_multi_config():
+      print language, 'does not support multiple build configurations'
+      sys.exit(1)
+
 build_steps = [jobset.JobSpec(['make',
                                '-j', '%d' % (multiprocessing.cpu_count() + 1),
                                'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
@@ -233,7 +281,8 @@
                                    itertools.chain.from_iterable(
                                        l.make_targets() for l in languages))))
                for cfg in build_configs] + list(set(
-                   jobset.JobSpec(cmdline)
+                   jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
+                   for cfg in build_configs
                    for l in languages
                    for cmdline in l.build_steps()))
 one_run = set(