diff --git a/examples/objective-c/helloworld/main.m b/examples/objective-c/helloworld/main.m
index 755dce33df9dd09dc3dbbb417239c4c7467999fd..bf357990a5679c94d6058b4c9e37a3d87accb40c 100644
--- a/examples/objective-c/helloworld/main.m
+++ b/examples/objective-c/helloworld/main.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/grpc.gemspec b/grpc.gemspec
index e305ea57ef3efa80f62560466701b6a493b888f0..e990948edf651603a5be6e83c2076463e234ed50 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -14,7 +14,6 @@ Gem::Specification.new do |s|
   s.license       = 'BSD-3-Clause'
 
   s.required_ruby_version = '>= 2.0.0'
-  s.requirements << 'libgrpc ~> 0.11.0 needs to be installed'
 
   s.files = %w( Makefile )
   s.files += %w( etc/roots.pem )
diff --git a/include/grpc/impl/codegen/sync.h b/include/grpc/impl/codegen/sync.h
index 7086b5d371143f8470d0b9bfe716123912383979..04ff0dc5bf9d734bb44fd32967cc387e9bdf58c3 100644
--- a/include/grpc/impl/codegen/sync.h
+++ b/include/grpc/impl/codegen/sync.h
@@ -115,7 +115,8 @@ GPR_API void gpr_cv_destroy(gpr_cv *cv);
 /* Atomically release *mu and wait on *cv.  When the calling thread is woken
    from *cv or the deadline abs_deadline is exceeded, execute gpr_mu_lock(mu)
    and return whether the deadline was exceeded.  Use
-   abs_deadline==gpr_inf_future for no deadline.  May return even when not
+   abs_deadline==gpr_inf_future for no deadline.  abs_deadline can be either
+   an absolute deadline, or a GPR_TIMESPAN.  May return even when not
    woken explicitly.  Requires:  *mu and *cv initialized; the calling thread
    holds an exclusive lock on *mu.  */
 GPR_API int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline);
diff --git a/include/grpc/impl/codegen/time.h b/include/grpc/impl/codegen/time.h
index b40c2b260cccf5f1616e7df8c5f90e70d4abad70..4ed1c3cbd86b5c9769a61ae6aad1197c6363c72c 100644
--- a/include/grpc/impl/codegen/time.h
+++ b/include/grpc/impl/codegen/time.h
@@ -102,14 +102,16 @@ GPR_API gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b);
 GPR_API gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b);
 GPR_API gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b);
 
-/* Return a timespec representing a given number of time units. LONG_MIN is
-   interpreted as gpr_inf_past, and LONG_MAX as gpr_inf_future.  */
-GPR_API gpr_timespec gpr_time_from_micros(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_nanos(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_millis(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_seconds(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_minutes(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_hours(long x, gpr_clock_type clock_type);
+/* Return a timespec representing a given number of time units. INT64_MIN is
+   interpreted as gpr_inf_past, and INT64_MAX as gpr_inf_future.  */
+GPR_API gpr_timespec gpr_time_from_micros(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec gpr_time_from_nanos(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec gpr_time_from_millis(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec
+gpr_time_from_seconds(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec
+gpr_time_from_minutes(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec gpr_time_from_hours(int64_t x, gpr_clock_type clock_type);
 
 GPR_API int32_t gpr_time_to_millis(gpr_timespec timespec);
 
diff --git a/setup.py b/setup.py
index 80828a3b4a9aa3d9cc9ec033648bee0f9e676fb4..3e8a7abe340c469f9970871acf27125c67ae641f 100644
--- a/setup.py
+++ b/setup.py
@@ -218,7 +218,7 @@ else:
 
 setuptools.setup(
     name='grpcio',
-    version='0.12.0b8',
+    version='0.12.0b9',
     license=LICENSE,
     ext_modules=CYTHON_EXTENSION_MODULES,
     packages=list(PACKAGES),
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 96b6f810248ac68cb38377539cd6223944e7c246..759340e00ef9365f4a3893a50ad7a0bb7e8b25c3 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -57,7 +57,7 @@ static HANDLE g_iocp;
 static DWORD deadline_to_millis_timeout(gpr_timespec deadline,
                                         gpr_timespec now) {
   gpr_timespec timeout;
-  static const int max_spin_polling_us = 10;
+  static const int64_t max_spin_polling_us = 10;
   if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
     return INFINITE;
   }
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index a8e2e22977753762bcd8cc05a2c371fffe0b16ec..19ee6650f006c25336d729964ae211b7820c372c 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -393,7 +393,7 @@ void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
                                          gpr_timespec now) {
   gpr_timespec timeout;
-  static const int max_spin_polling_us = 10;
+  static const int64_t max_spin_polling_us = 10;
   if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
     return -1;
   }
diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c
index 2c97ee18be1090691c7086d354383f838022489d..9daecd2e18a772c6a3fb7e820ffd01b866af72ca 100644
--- a/src/core/support/stack_lockfree.c
+++ b/src/core/support/stack_lockfree.c
@@ -99,7 +99,7 @@ gpr_stack_lockfree *gpr_stack_lockfree_create(size_t entries) {
 
   /* Point the head at reserved dummy entry */
   stack->head.contents.index = INVALID_ENTRY_INDEX;
-  /* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
+/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
 #ifdef GPR_ARCH_64
   stack->head.contents.pad = 0;
 #endif
diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c
index 84d412a75f0de5f09d9a510a7f77a6396f686e88..41998ebcb6b2c5db483f71f87c4ac9f3aec66741 100644
--- a/src/core/support/sync_win32.c
+++ b/src/core/support/sync_win32.c
@@ -87,6 +87,7 @@ int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
       0) {
     SleepConditionVariableCS(cv, &mu->cs, INFINITE);
   } else {
+    abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
     gpr_timespec now = gpr_now(abs_deadline.clock_type);
     int64_t now_ms = (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000;
     int64_t deadline_ms =
diff --git a/src/core/support/time.c b/src/core/support/time.c
index ac8c3bcde5b0da3597e4f6dcff9a5e6dd9186bcc..423d12ffc0fd052da61b22d1322ee9e54ca1d04b 100644
--- a/src/core/support/time.c
+++ b/src/core/support/time.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -83,12 +83,12 @@ gpr_timespec gpr_inf_past(gpr_clock_type type) {
 /* TODO(ctiller): consider merging _nanos, _micros, _millis into a single
    function for maintainability. Similarly for _seconds, _minutes, and _hours */
 
-gpr_timespec gpr_time_from_nanos(long ns, gpr_clock_type type) {
+gpr_timespec gpr_time_from_nanos(int64_t ns, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (ns == LONG_MAX) {
+  if (ns == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (ns == LONG_MIN) {
+  } else if (ns == INT64_MIN) {
     result = gpr_inf_past(type);
   } else if (ns >= 0) {
     result.tv_sec = ns / GPR_NS_PER_SEC;
@@ -101,12 +101,12 @@ gpr_timespec gpr_time_from_nanos(long ns, gpr_clock_type type) {
   return result;
 }
 
-gpr_timespec gpr_time_from_micros(long us, gpr_clock_type type) {
+gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (us == LONG_MAX) {
+  if (us == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (us == LONG_MIN) {
+  } else if (us == INT64_MIN) {
     result = gpr_inf_past(type);
   } else if (us >= 0) {
     result.tv_sec = us / 1000000;
@@ -119,12 +119,12 @@ gpr_timespec gpr_time_from_micros(long us, gpr_clock_type type) {
   return result;
 }
 
-gpr_timespec gpr_time_from_millis(long ms, gpr_clock_type type) {
+gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (ms == LONG_MAX) {
+  if (ms == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (ms == LONG_MIN) {
+  } else if (ms == INT64_MIN) {
     result = gpr_inf_past(type);
   } else if (ms >= 0) {
     result.tv_sec = ms / 1000;
@@ -137,12 +137,12 @@ gpr_timespec gpr_time_from_millis(long ms, gpr_clock_type type) {
   return result;
 }
 
-gpr_timespec gpr_time_from_seconds(long s, gpr_clock_type type) {
+gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (s == LONG_MAX) {
+  if (s == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (s == LONG_MIN) {
+  } else if (s == INT64_MIN) {
     result = gpr_inf_past(type);
   } else {
     result.tv_sec = s;
@@ -151,12 +151,12 @@ gpr_timespec gpr_time_from_seconds(long s, gpr_clock_type type) {
   return result;
 }
 
-gpr_timespec gpr_time_from_minutes(long m, gpr_clock_type type) {
+gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (m >= LONG_MAX / 60) {
+  if (m >= INT64_MAX / 60) {
     result = gpr_inf_future(type);
-  } else if (m <= LONG_MIN / 60) {
+  } else if (m <= INT64_MIN / 60) {
     result = gpr_inf_past(type);
   } else {
     result.tv_sec = m * 60;
@@ -165,12 +165,12 @@ gpr_timespec gpr_time_from_minutes(long m, gpr_clock_type type) {
   return result;
 }
 
-gpr_timespec gpr_time_from_hours(long h, gpr_clock_type type) {
+gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (h >= LONG_MAX / 3600) {
+  if (h >= INT64_MAX / 3600) {
     result = gpr_inf_future(type);
-  } else if (h <= LONG_MIN / 3600) {
+  } else if (h <= INT64_MIN / 3600) {
     result = gpr_inf_past(type);
   } else {
     result.tv_sec = h * 3600;
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index 095883c66da92e8266068ed282f612a050daeff7..cafecf10465818fd93c63e0cccd1fb4604b3f289 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -75,6 +75,9 @@ int grpc_chttp2_unlocking_check_writes(
 
   GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
                                   transport_global, outgoing_window);
+  bool is_window_available = transport_writing->outgoing_window > 0;
+  grpc_chttp2_list_flush_writing_stalled_by_transport(transport_writing,
+                                                      is_window_available);
 
   /* for each grpc_chttp2_stream that's become writable, frame it's data
      (according to available window sizes) and add to the output buffer */
@@ -329,10 +332,6 @@ void grpc_chttp2_cleanup_writing(
     grpc_chttp2_transport_writing *transport_writing) {
   grpc_chttp2_stream_writing *stream_writing;
   grpc_chttp2_stream_global *stream_global;
-  bool is_window_available = transport_writing->outgoing_window > 0;
-
-  grpc_chttp2_list_flush_writing_stalled_by_transport(transport_writing,
-                                                      is_window_available);
 
   while (grpc_chttp2_list_pop_written_stream(
       transport_global, transport_writing, &stream_global, &stream_writing)) {
diff --git a/src/node/ext/timeval.cc b/src/node/ext/timeval.cc
index 64015e8412e59a2bf9607ae47ee21b0af9e7c470..c8f8534cfa7fd6abadfe8f1459cd7f9cc7c43f68 100644
--- a/src/node/ext/timeval.cc
+++ b/src/node/ext/timeval.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
  */
 
 #include <limits>
+#include <cstdint>
 
 #include "grpc/grpc.h"
 #include "grpc/support/time.h"
@@ -46,7 +47,7 @@ gpr_timespec MillisecondsToTimespec(double millis) {
   } else if (millis == -std::numeric_limits<double>::infinity()) {
     return gpr_inf_past(GPR_CLOCK_REALTIME);
   } else {
-    return gpr_time_from_micros(static_cast<long>(millis * 1000),
+    return gpr_time_from_micros(static_cast<int64_t>(millis * 1000),
                                 GPR_CLOCK_REALTIME);
   }
 }
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index 1888dea1b47e8eb5475add666bfe78483f4fc752..8661ae6f97273d0258c4f747133b28f8ef5f7eea 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 7a676060c163ce169d3d5a3fb7394a65621b7db7..7e55a473d74689f1fa27298200d59a30b24e9cd1 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h
index 69a115e88cf92bc137775b49094023a1be4f6a5a..82c0ad6cf631fd56f7e7904df7421da9efc94b50 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.h
+++ b/src/objective-c/GRPCClient/private/GRPCHost.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index f750841a4464c7a760281d4729c922080f8972c4..eb1db899b700b8d899b8d47ee6a44825e779e5a6 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 9d6e0170269fe12febbbc75f3864897fd4eee64e..9c85e0ee1bd08d24d8a39bcd634769d14d38ed96 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index 9e14b967e0aa3dcd1e4fc422ab1b2989f59b7061..fa4ea99ea9e68e0e6ef965bb4ba1655ea0656529 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index 579bac7b8af7f03a43c4f828efb10326ac283767..b1836bf5be3ffb5647d96971d2a4de0f8156ffc5 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h
index f85d416db8fc28917d6d51ad0f1afd23e2fe8b72..6d0a6e06c0002fe42d899ab0665eb8c86dcd4144 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.h
+++ b/src/python/grpcio/grpc/_cython/imports.generated.h
@@ -655,22 +655,22 @@ extern gpr_time_add_type gpr_time_add_import;
 typedef gpr_timespec(*gpr_time_sub_type)(gpr_timespec a, gpr_timespec b);
 extern gpr_time_sub_type gpr_time_sub_import;
 #define gpr_time_sub gpr_time_sub_import
-typedef gpr_timespec(*gpr_time_from_micros_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_micros_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_micros_type gpr_time_from_micros_import;
 #define gpr_time_from_micros gpr_time_from_micros_import
-typedef gpr_timespec(*gpr_time_from_nanos_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_nanos_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_nanos_type gpr_time_from_nanos_import;
 #define gpr_time_from_nanos gpr_time_from_nanos_import
-typedef gpr_timespec(*gpr_time_from_millis_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_millis_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_millis_type gpr_time_from_millis_import;
 #define gpr_time_from_millis gpr_time_from_millis_import
-typedef gpr_timespec(*gpr_time_from_seconds_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_seconds_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_seconds_type gpr_time_from_seconds_import;
 #define gpr_time_from_seconds gpr_time_from_seconds_import
-typedef gpr_timespec(*gpr_time_from_minutes_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_minutes_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_minutes_type gpr_time_from_minutes_import;
 #define gpr_time_from_minutes gpr_time_from_minutes_import
-typedef gpr_timespec(*gpr_time_from_hours_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_hours_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_hours_type gpr_time_from_hours_import;
 #define gpr_time_from_hours gpr_time_from_hours_import
 typedef int32_t(*gpr_time_to_millis_type)(gpr_timespec timespec);
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 45e9b475743f7809d88ff4cee515ff96e8cf2ae4..618ae5e7fcfe77ea8d16c6f223a10322719212bc 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -655,22 +655,22 @@ extern gpr_time_add_type gpr_time_add_import;
 typedef gpr_timespec(*gpr_time_sub_type)(gpr_timespec a, gpr_timespec b);
 extern gpr_time_sub_type gpr_time_sub_import;
 #define gpr_time_sub gpr_time_sub_import
-typedef gpr_timespec(*gpr_time_from_micros_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_micros_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_micros_type gpr_time_from_micros_import;
 #define gpr_time_from_micros gpr_time_from_micros_import
-typedef gpr_timespec(*gpr_time_from_nanos_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_nanos_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_nanos_type gpr_time_from_nanos_import;
 #define gpr_time_from_nanos gpr_time_from_nanos_import
-typedef gpr_timespec(*gpr_time_from_millis_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_millis_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_millis_type gpr_time_from_millis_import;
 #define gpr_time_from_millis gpr_time_from_millis_import
-typedef gpr_timespec(*gpr_time_from_seconds_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_seconds_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_seconds_type gpr_time_from_seconds_import;
 #define gpr_time_from_seconds gpr_time_from_seconds_import
-typedef gpr_timespec(*gpr_time_from_minutes_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_minutes_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_minutes_type gpr_time_from_minutes_import;
 #define gpr_time_from_minutes gpr_time_from_minutes_import
-typedef gpr_timespec(*gpr_time_from_hours_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_hours_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_hours_type gpr_time_from_hours_import;
 #define gpr_time_from_hours gpr_time_from_hours_import
 typedef int32_t(*gpr_time_to_millis_type)(gpr_timespec timespec);
diff --git a/templates/grpc.gemspec.template b/templates/grpc.gemspec.template
index 9d034ddba125962c6c96323581cf683836d7eb44..c4987a6725feee6ce6d053d4aaf9abec65a2bb09 100644
--- a/templates/grpc.gemspec.template
+++ b/templates/grpc.gemspec.template
@@ -16,7 +16,6 @@
     s.license       = 'BSD-3-Clause'
 
     s.required_ruby_version = '>= 2.0.0'
-    s.requirements << 'libgrpc ~> 0.11.0 needs to be installed'
 
     s.files = %w( Makefile )
     s.files += %w( etc/roots.pem )
diff --git a/test/core/statistics/census_log_tests.c b/test/core/statistics/census_log_tests.c
index aac20fd96a2ea87a821df4d57f9df26811d392cd..77cc57d4d63b75ea050fd08873d136e7a11a4c69 100644
--- a/test/core/statistics/census_log_tests.c
+++ b/test/core/statistics/census_log_tests.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -237,8 +237,8 @@ static void reader_thread(void *arg) {
   gpr_timespec interval;
   int counter = 0;
   printf("   Reader starting\n");
-  interval = gpr_time_from_micros(args->read_iteration_interval_in_msec * 1000,
-                                  GPR_TIMESPAN);
+  interval = gpr_time_from_micros(
+      (int64_t)args->read_iteration_interval_in_msec * 1000, GPR_TIMESPAN);
   gpr_mu_lock(args->mu);
   while (!args->stop_flag && records_read < args->total_records) {
     gpr_cv_wait(&args->stop, args->mu, interval);
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
index 0149bc3afdeee54333804680a5de3246d85b6fb9..d311eb136a6a27b3bf78866e30dd5c3adfcff324 100644
--- a/test/core/support/sync_test.c
+++ b/test/core/support/sync_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -251,7 +251,7 @@ static void test(const char *name, void (*body)(void *m),
   gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   gpr_timespec time_taken;
   gpr_timespec deadline = gpr_time_add(
-      start, gpr_time_from_micros(timeout_s * 1000000, GPR_TIMESPAN));
+      start, gpr_time_from_micros((int64_t)timeout_s * 1000000, GPR_TIMESPAN));
   fprintf(stderr, "%s:", name);
   while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
     iterations <<= 1;
diff --git a/test/core/support/time_test.c b/test/core/support/time_test.c
index fc26f94d29a1a774e554a772438c4a166e2c0e78..6cc3786df12be55abceb93f41eaf8681365ef6a9 100644
--- a/test/core/support/time_test.c
+++ b/test/core/support/time_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -125,15 +125,15 @@ static void test_values(void) {
   }
 
   /* Test possible overflow in conversion of -ve values. */
-  x = gpr_time_from_micros(-(LONG_MAX - 999997), GPR_TIMESPAN);
+  x = gpr_time_from_micros(-(INT64_MAX - 999997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
-  x = gpr_time_from_nanos(-(LONG_MAX - 999999997), GPR_TIMESPAN);
+  x = gpr_time_from_nanos(-(INT64_MAX - 999999997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
-  x = gpr_time_from_millis(-(LONG_MAX - 997), GPR_TIMESPAN);
+  x = gpr_time_from_millis(-(INT64_MAX - 997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
diff --git a/test/core/transport/chttp2/timeout_encoding_test.c b/test/core/transport/chttp2/timeout_encoding_test.c
index f0e8ec386fcf6518b5bdf1b1dc88c31d65f90138..483e79fb2536ccf162c506e4ec81a9deb52df329 100644
--- a/test/core/transport/chttp2/timeout_encoding_test.c
+++ b/test/core/transport/chttp2/timeout_encoding_test.c
@@ -93,7 +93,7 @@ static void assert_decodes_as(const char *buffer, gpr_timespec expected) {
 }
 
 void decode_suite(char ext,
-                  gpr_timespec (*answer)(long x, gpr_clock_type clock)) {
+                  gpr_timespec (*answer)(int64_t x, gpr_clock_type clock)) {
   long test_vals[] = {1,       12,       123,       1234,     12345,   123456,
                       1234567, 12345678, 123456789, 98765432, 9876543, 987654,
                       98765,   9876,     987,       98,       9};
diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h
index 15b71747fb5963bff8f04f7f9e12e78b25f9583f..f6bb2e1f72a2317bca2acf0e18cbff00d04f4609 100644
--- a/test/core/util/test_config.h
+++ b/test/core/util/test_config.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,16 +54,16 @@ extern double g_fixture_slowdown_factor;
   (GRPC_TEST_SLOWDOWN_BUILD_FACTOR * GRPC_TEST_SLOWDOWN_MACHINE_FACTOR * \
    g_fixture_slowdown_factor)
 
-#define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x)                               \
-  gpr_time_add(                                                           \
-      gpr_now(GPR_CLOCK_MONOTONIC),                                       \
-      gpr_time_from_millis((long)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
+#define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x)                                  \
+  gpr_time_add(                                                              \
+      gpr_now(GPR_CLOCK_MONOTONIC),                                          \
+      gpr_time_from_millis((int64_t)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
                            GPR_TIMESPAN))
 
-#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x)                                \
-  gpr_time_add(                                                           \
-      gpr_now(GPR_CLOCK_MONOTONIC),                                       \
-      gpr_time_from_micros((long)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
+#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x)                                   \
+  gpr_time_add(                                                              \
+      gpr_now(GPR_CLOCK_MONOTONIC),                                          \
+      gpr_time_from_micros((int64_t)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
                            GPR_TIMESPAN))
 
 #ifndef GRPC_TEST_CUSTOM_PICK_PORT
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 4c7caa9b878af71df34ed1e4e652bd10b9513780..dd7a8e5ed2c9aa1465a5377106af917442f8ea3b 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -55,7 +55,9 @@ using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
 
-const int kNumThreads = 100;  // Number of threads
+const int kNumThreads = 100; // Number of threads
+const int kNumAsyncSendThreads = 2;
+const int kNumAsyncReceiveThreads = 50;
 const int kNumRpcs = 1000;    // Number of RPCs per thread
 
 namespace grpc {
@@ -273,7 +275,7 @@ class AsyncClientEnd2endTest : public ::testing::Test {
     for (int i = 0; i < num_rpcs; ++i) {
       AsyncClientCall* call = new AsyncClientCall;
       EchoRequest request;
-      request.set_message("Hello");
+      request.set_message("Hello: " + std::to_string(i));
       call->response_reader =
           common_.GetStub()->AsyncEcho(&call->context, request, &cq_);
       call->response_reader->Finish(&call->response, &call->status,
@@ -290,7 +292,9 @@ class AsyncClientEnd2endTest : public ::testing::Test {
       bool ok = false;
       if (!cq_.Next(&got_tag, &ok)) break;
       AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
-      GPR_ASSERT(ok);
+      if (!ok) {
+        gpr_log(GPR_DEBUG, "Error: %d", call->status.error_code());
+      }
       delete call;
 
       bool notify;
@@ -315,22 +319,22 @@ class AsyncClientEnd2endTest : public ::testing::Test {
 TEST_F(AsyncClientEnd2endTest, ThreadStress) {
   common_.ResetStub();
   std::vector<std::thread*> send_threads, completion_threads;
-  for (int i = 0; i < kNumThreads / 2; ++i) {
+  for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
     completion_threads.push_back(new std::thread(
         &AsyncClientEnd2endTest_ThreadStress_Test::AsyncCompleteRpc, this));
   }
-  for (int i = 0; i < kNumThreads / 2; ++i) {
+  for (int i = 0; i < kNumAsyncSendThreads; ++i) {
     send_threads.push_back(
         new std::thread(&AsyncClientEnd2endTest_ThreadStress_Test::AsyncSendRpc,
                         this, kNumRpcs));
   }
-  for (int i = 0; i < kNumThreads / 2; ++i) {
+  for (int i = 0; i < kNumAsyncSendThreads; ++i) {
     send_threads[i]->join();
     delete send_threads[i];
   }
 
   Wait();
-  for (int i = 0; i < kNumThreads / 2; ++i) {
+  for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
     completion_threads[i]->join();
     delete completion_threads[i];
   }
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index 6b6294ba518b32361d91a4898dd2b5c7ee9d9752..f3f8f37051b0778016ac3a4eface434d13f646f0 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -96,8 +96,7 @@ class ClientRpcContextUnaryImpl : public ClientRpcContext {
       std::function<
           std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
               BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&,
-              CompletionQueue*)>
-          start_req,
+              CompletionQueue*)> start_req,
       std::function<void(grpc::Status, ResponseType*)> on_done)
       : ClientRpcContext(channel_id),
         context_(),
@@ -143,8 +142,7 @@ class ClientRpcContextUnaryImpl : public ClientRpcContext {
   std::function<void(grpc::Status, ResponseType*)> callback_;
   std::function<std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
       BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&,
-      CompletionQueue*)>
-      start_req_;
+      CompletionQueue*)> start_req_;
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>
@@ -164,12 +162,11 @@ class AsyncClient : public ClientImpl<StubType, RequestType> {
   using ClientImpl<StubType, RequestType>::cores_;
   using ClientImpl<StubType, RequestType>::channels_;
   using ClientImpl<StubType, RequestType>::request_;
-  AsyncClient(
-      const ClientConfig& config,
-      std::function<ClientRpcContext*(int, StubType*, const RequestType&)>
-          setup_ctx,
-      std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)>
-          create_stub)
+  AsyncClient(const ClientConfig& config,
+              std::function<ClientRpcContext*(int, StubType*,
+                                              const RequestType&)> setup_ctx,
+              std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)>
+                  create_stub)
       : ClientImpl<StubType, RequestType>(config, create_stub),
         num_async_threads_(NumThreads(config)),
         channel_lock_(new std::mutex[config.client_channels()]),
@@ -411,8 +408,7 @@ class ClientRpcContextStreamingImpl : public ClientRpcContext {
       std::function<std::unique_ptr<
           grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>(
           BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*,
-          void*)>
-          start_req,
+          void*)> start_req,
       std::function<void(grpc::Status, ResponseType*)> on_done)
       : ClientRpcContext(channel_id),
         context_(),
@@ -464,10 +460,10 @@ class ClientRpcContextStreamingImpl : public ClientRpcContext {
   ResponseType response_;
   bool (ClientRpcContextStreamingImpl::*next_state_)(bool, Histogram*);
   std::function<void(grpc::Status, ResponseType*)> callback_;
-  std::function<std::unique_ptr<
-      grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>(
-      BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*, void*)>
-      start_req_;
+  std::function<
+      std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>(
+          BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*,
+          void*)> start_req_;
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>
@@ -511,8 +507,7 @@ class ClientRpcContextGenericStreamingImpl : public ClientRpcContext {
       int channel_id, grpc::GenericStub* stub, const ByteBuffer& req,
       std::function<std::unique_ptr<grpc::GenericClientAsyncReaderWriter>(
           grpc::GenericStub*, grpc::ClientContext*,
-          const grpc::string& method_name, CompletionQueue*, void*)>
-          start_req,
+          const grpc::string& method_name, CompletionQueue*, void*)> start_req,
       std::function<void(grpc::Status, ByteBuffer*)> on_done)
       : ClientRpcContext(channel_id),
         context_(),
@@ -569,8 +564,7 @@ class ClientRpcContextGenericStreamingImpl : public ClientRpcContext {
   std::function<void(grpc::Status, ByteBuffer*)> callback_;
   std::function<std::unique_ptr<grpc::GenericClientAsyncReaderWriter>(
       grpc::GenericStub*, grpc::ClientContext*, const grpc::string&,
-      CompletionQueue*, void*)>
-      start_req_;
+      CompletionQueue*, void*)> start_req_;
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::GenericClientAsyncReaderWriter> stream_;
diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h
index 4b2b400c0ce9ec3aa10e30ce0b47f83cbb478b48..3af61f73917f35b9bdf929b6cb0c7009bb1b09f5 100644
--- a/test/cpp/qps/driver.h
+++ b/test/cpp/qps/driver.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/cpp/util/time_test.cc b/test/cpp/util/time_test.cc
index 1e501dfd28877413fd5ff4274fd1c1c37067d2b8..48c6ce7697ca0b923bbd51fec6635790e530edcb 100644
--- a/test/cpp/util/time_test.cc
+++ b/test/cpp/util/time_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@ namespace {
 class TimeTest : public ::testing::Test {};
 
 TEST_F(TimeTest, AbsolutePointTest) {
-  long us = 10000000L;
+  int64_t us = 10000000L;
   gpr_timespec ts = gpr_time_from_micros(us, GPR_TIMESPAN);
   ts.clock_type = GPR_CLOCK_REALTIME;
   system_clock::time_point tp{microseconds(us)};
diff --git a/test/distrib/csharp/run_distrib_test.sh b/test/distrib/csharp/run_distrib_test.sh
index 5a01c918757f677027cc9163fea977c5cb293d09..8ddb4c4bffe16877a2da6466f3534e20ff3a36c1 100755
--- a/test/distrib/csharp/run_distrib_test.sh
+++ b/test/distrib/csharp/run_distrib_test.sh
@@ -32,7 +32,7 @@ set -ex
 
 cd $(dirname $0)
 
-unzip "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets.zip" -d TestNugetFeed
+unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets.zip" -d TestNugetFeed
 
 # TODO(jtattermusch): replace the version number
 ./update_version.sh 0.13.0
diff --git a/test/distrib/csharp/update_version.sh b/test/distrib/csharp/update_version.sh
index 569f7ff4bd5270e8445f46ba81992e97d39dac2d..f2554e89981c571b9e2b53b39b906aeb78177b7e 100755
--- a/test/distrib/csharp/update_version.sh
+++ b/test/distrib/csharp/update_version.sh
@@ -33,4 +33,4 @@ set -e
 cd $(dirname $0)
 
 # Replaces version placeholder with value provided as first argument.
-sed -i "s/__GRPC_NUGET_VERSION__/$1/g" DistribTest/packages.config DistribTest/DistribTest.csproj
+sed -ibak "s/__GRPC_NUGET_VERSION__/$1/g" DistribTest/packages.config DistribTest/DistribTest.csproj
diff --git a/test/distrib/node/run_distrib_test.sh b/test/distrib/node/run_distrib_test.sh
index 90637cc01d0f402508cffd4098e10ae236a08756..ac9e7d70907981f0433897512371fcd63e5a239d 100755
--- a/test/distrib/node/run_distrib_test.sh
+++ b/test/distrib/node/run_distrib_test.sh
@@ -32,7 +32,12 @@ set -ex
 
 cd $(dirname $0)
 
-nvm install $1
+NODE_VERSION="$1"
+
+# make sure nvm is available
+source ~/.nvm/nvm.sh || true
+
+nvm install $NODE_VERSION
 
 npm install -g node-static
 
diff --git a/test/distrib/python/distribtest.py b/test/distrib/python/distribtest.py
index 428ffe2b34a296cf2eb437aa1954c128f01597aa..66c1f88796454353c2efd6a55d2fe7df44ea8188 100644
--- a/test/distrib/python/distribtest.py
+++ b/test/distrib/python/distribtest.py
@@ -1,3 +1,32 @@
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 from grpc.beta import implementations
 
 # This code doesn't do much but makes sure the native extension is loaded
diff --git a/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile b/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile
index bd40ab2b4cb2557aa7fda2ce620bf1890bc48a30..8b97d8bb5a3be1aaec3ae73ac5a7c8c39f987a11 100644
--- a/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile
+++ b/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile
@@ -29,8 +29,8 @@
 
 FROM 32bit/debian:jessie
 
-RUN apt-get update && apt-get install -y git
+RUN apt-get update && apt-get install -y curl
 
 # Install nvm
 RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
diff --git a/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile b/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile
index cb6ec22d0acdd387de805a8054e7ef0c92beb329..e9cf99142b8c0783848ca4091910c81accd7527f 100644
--- a/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile
+++ b/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile
@@ -30,3 +30,8 @@
 FROM 32bit/debian:jessie
 
 RUN apt-get update && apt-get install -y python python-pip
+
+# docker is running on a 64-bit machine, so we need to
+# override "uname -m" to report i686 instead of x86_64, otherwise
+# python will choose a wrong binary package to install.
+ENTRYPOINT ["linux32"]
diff --git a/tools/jenkins/docker_run_tests.sh b/tools/jenkins/docker_run_tests.sh
index 26e5585d2d8ba812add9903fc09b005378910ff3..12874386a3c7951eaa9a1674631893817505a8fe 100755
--- a/tools/jenkins/docker_run_tests.sh
+++ b/tools/jenkins/docker_run_tests.sh
@@ -43,8 +43,6 @@ chown `whoami` $XDG_CACHE_HOME
 mkdir -p /var/local/git
 git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
 
-nvm use 0.12 || true
-
 if [ -x "$(command -v rvm)" ]
 then
   rvm use ruby-2.1
diff --git a/tools/run_tests/build_node.sh b/tools/run_tests/build_node.sh
index 8f2ab4413a20cde4f084866d2e2df7966c66d730..9c4af071856d82b646dfcd2a7ce7338ec1596def 100755
--- a/tools/run_tests/build_node.sh
+++ b/tools/run_tests/build_node.sh
@@ -29,8 +29,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
 set -ex
 
+nvm use $NODE_VERSION
+
 CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
diff --git a/tools/run_tests/build_package_python.sh b/tools/run_tests/build_package_python.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2511a6ae46598c268fcc1411c3b2b0bbe32a1008
--- /dev/null
+++ b/tools/run_tests/build_package_python.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -ex
+
+cd $(dirname $0)/../..
+
+mkdir -p artifacts/
+
+# All the python packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
+cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=python,platform={windows,linux,macos}/artifacts/* artifacts/ || true
+
+# TODO: all the artifact builder configurations generate a grpcio-VERSION.tar.gz
+# source distribution package, and only one of them will end up
+# in the artifacts/ directory. They should be all equivalent though.
diff --git a/tools/run_tests/build_package_ruby.sh b/tools/run_tests/build_package_ruby.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1a5b94348d8b1017c08e67120fad28d154b8a999
--- /dev/null
+++ b/tools/run_tests/build_package_ruby.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -ex
+
+cd $(dirname $0)/../..
+
+mkdir -p artifacts/
+
+# All the ruby packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
+cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=ruby,platform={windows,linux,macos}/artifacts/* artifacts/ || true
+
+# TODO: all the artifact builder configurations generate a grpc-VERSION.gem
+# source distribution package, and only one of them will end up
+# in the artifacts/ directory. They should be all equivalent though.
diff --git a/tools/run_tests/distribtest_targets.py b/tools/run_tests/distribtest_targets.py
index a1e45ece9dcd1425feeb77848a03fefa079e2a20..fc7dd17145830d5b686482d4f0eba3117cbf707a 100644
--- a/tools/run_tests/distribtest_targets.py
+++ b/tools/run_tests/distribtest_targets.py
@@ -55,28 +55,49 @@ def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
   return jobspec
 
 
+def create_jobspec(name, cmdline, environ=None, shell=False,
+                   flake_retries=0, timeout_retries=0):
+  """Creates jobspec."""
+  jobspec = jobset.JobSpec(
+          cmdline=cmdline,
+          environ=environ,
+          shortname='distribtest.%s' % (name),
+          timeout_seconds=10*60,
+          flake_retries=flake_retries,
+          timeout_retries=timeout_retries,
+          shell=shell)
+  return jobspec
+
+
 class CSharpDistribTest(object):
   """Tests C# NuGet package"""
 
-  def __init__(self, platform, arch, docker_suffix):
-    self.name = 'csharp_nuget_%s_%s_%s' % (platform, arch, docker_suffix)
+  def __init__(self, platform, arch, docker_suffix=None):
+    self.name = 'csharp_nuget_%s_%s' % (platform, arch)
     self.platform = platform
     self.arch = arch
     self.docker_suffix = docker_suffix
-    self.labels = ['distribtest', 'csharp', platform, arch, docker_suffix]
+    self.labels = ['distribtest', 'csharp', platform, arch]
+    if docker_suffix:
+      self.name += '_%s' % docker_suffix
+      self.labels.append(docker_suffix)
 
   def pre_build_jobspecs(self):
     return []
 
   def build_jobspec(self):
-    if not self.platform == 'linux':
-      raise Exception("Not supported yet.")
-
-    return create_docker_jobspec(self.name,
+    if self.platform == 'linux':
+      return create_docker_jobspec(self.name,
           'tools/dockerfile/distribtest/csharp_%s_%s' % (
               self.docker_suffix,
               self.arch),
           'test/distrib/csharp/run_distrib_test.sh')
+    elif self.platform == 'macos':
+      return create_jobspec(self.name,
+          ['test/distrib/csharp/run_distrib_test.sh'],
+          environ={'EXTERNAL_GIT_ROOT': '../../..'})
+    else:
+      raise Exception("Not supported yet.")
 
   def __str__(self):
     return self.name
@@ -105,8 +126,7 @@ class NodeDistribTest(object):
                                  'tools/dockerfile/distribtest/node_%s_%s' % (
                                      self.docker_suffix,
                                      self.arch),
-                                 # bash -l needed to make nvm available
-                                 'bash -l test/distrib/node/run_distrib_test.sh %s' % (
+                                 'test/distrib/node/run_distrib_test.sh %s' % (
                                      self.node_version))
     def __str__(self):
       return self.name
@@ -176,6 +196,7 @@ def targets():
           CSharpDistribTest('linux', 'x64', 'ubuntu1504'),
           CSharpDistribTest('linux', 'x64', 'ubuntu1510'),
           CSharpDistribTest('linux', 'x64', 'ubuntu1604'),
+          CSharpDistribTest('macos', 'x86'),
           PythonDistribTest('linux', 'x64', 'wheezy'),
           PythonDistribTest('linux', 'x64', 'jessie'),
           PythonDistribTest('linux', 'x86', 'jessie'),
diff --git a/tools/run_tests/interop_html_report.template b/tools/run_tests/interop_html_report.template
index 114a508c319ea103a779b8185e2fcac27b246b33..46cce426b7af3e05adfe568a59e150a997a304f5 100644
--- a/tools/run_tests/interop_html_report.template
+++ b/tools/run_tests/interop_html_report.template
@@ -64,17 +64,8 @@
   % endif
 </%def>
 
-% if num_failures > 1:
-  <p><h2><font color="red">${num_failures} tests failed!</font></h2></p>
-% elif num_failures:
-  <p><h2><font color="red">${num_failures} test failed!</font></h2></p>
-% else:
-  <p><h2><font color="green">All tests passed!</font></h2></p>
-% endif
-
-% if cloud_to_prod:
+<%def name="display_cloud_to_prod_result(prod_server)">
   ## Each column header is the client language.
-  <h2>Cloud to Prod</h2>
   <table style="width:100%" border="1">
   <tr bgcolor="#00BFFF">
   <th>Client languages &#9658;<br/>Test Cases &#9660;</th>
@@ -87,15 +78,32 @@
     % for client_lang in client_langs:
       <% 
         if test_case in auth_test_cases:
-          shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case)
+          shortname = 'cloud_to_prod_auth:%s:%s:%s' % (
+              prod_server, client_lang, test_case)
         else:
-          shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case)
+          shortname = 'cloud_to_prod:%s:%s:%s' % (
+              prod_server, client_lang, test_case)
       %>
       ${fill_one_test_result(shortname, resultset)}
     % endfor
     </tr> 
   % endfor
   </table>
+</%def>
+
+% if num_failures > 1:
+  <p><h2><font color="red">${num_failures} tests failed!</font></h2></p>
+% elif num_failures:
+  <p><h2><font color="red">${num_failures} test failed!</font></h2></p>
+% else:
+  <p><h2><font color="green">All tests passed!</font></h2></p>
+% endif
+
+% if cloud_to_prod:
+  % for prod_server in prod_servers:
+    <h2>Cloud to ${prod_server}</h2>
+    ${display_cloud_to_prod_result(prod_server)}
+  % endfor
 % endif
 
 % if http2_interop:
@@ -108,7 +116,9 @@
     <th>${server_lang}</th>
   % endfor
   % if cloud_to_prod:
-    <th>prod</th>
+    % for prod_server in prod_servers:
+      <th>${prod_server}</th>
+    % endfor
   % endif
   </tr>
   % for test_case in http2_cases:
@@ -122,8 +132,10 @@
       ${fill_one_http2_test_result(shortname, resultset)}
     % endfor
     % if cloud_to_prod:
-      <% shortname = 'cloud_to_prod:http2:%s' % test_case %>
-      ${fill_one_http2_test_result(shortname, resultset)}
+      % for prod_server in prod_servers:
+        <% shortname = 'cloud_to_prod:%s:http2:%s' % (prod_server, test_case) %>
+        ${fill_one_http2_test_result(shortname, resultset)}
+      % endfor
     % endif
     </tr>
   % endfor
diff --git a/tools/run_tests/package_targets.py b/tools/run_tests/package_targets.py
index 997bc57cc5a2d7718aa891efb67eb6eb181b71df..4ca8279f1bfa529783b2b2463e582cec7978c7dc 100644
--- a/tools/run_tests/package_targets.py
+++ b/tools/run_tests/package_targets.py
@@ -68,11 +68,11 @@ def create_jobspec(name, cmdline, environ=None, cwd=None, shell=False,
   return jobspec
 
 
-class CSharpNugetTarget:
+class CSharpPackage:
   """Builds C# nuget packages."""
 
   def __init__(self):
-    self.name = 'csharp_nuget'
+    self.name = 'csharp_package'
     self.labels = ['package', 'csharp', 'windows']
 
   def pre_build_jobspecs(self):
@@ -87,11 +87,12 @@ class CSharpNugetTarget:
   def __str__(self):
     return self.name
 
-class NodeNpmBinaryTarget:
-  """Builds Node NPM package and collects binaries"""
+
+class NodePackage:
+  """Builds Node NPM package and collects precompiled binaries"""
 
   def __init__(self):
-    self.name = 'node_npm_binary'
+    self.name = 'node_package'
     self.labels = ['package', 'node', 'linux']
 
   def pre_build_jobspecs(self):
@@ -103,6 +104,44 @@ class NodeNpmBinaryTarget:
         'tools/dockerfile/grpc_artifact_linux_x64',
         'tools/run_tests/build_package_node.sh')
 
+
+class RubyPackage:
+  """Collects ruby gems created in the artifact phase"""
+
+  def __init__(self):
+    self.name = 'ruby_package'
+    self.labels = ['package', 'ruby', 'linux']
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    return create_docker_jobspec(
+        self.name,
+        'tools/dockerfile/grpc_artifact_linux_x64',
+        'tools/run_tests/build_package_ruby.sh')
+
+
+class PythonPackage:
+  """Collects python eggs and wheels created in the artifact phase"""
+
+  def __init__(self):
+    self.name = 'python_package'
+    self.labels = ['package', 'python', 'linux']
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    return create_docker_jobspec(
+        self.name,
+        'tools/dockerfile/grpc_artifact_linux_x64',
+        'tools/run_tests/build_package_python.sh')
+
+
 def targets():
   """Gets list of supported targets"""
-  return [CSharpNugetTarget(), NodeNpmBinaryTarget()]
+  return [CSharpPackage(),
+          NodePackage(),
+          RubyPackage(),
+          PythonPackage()]
diff --git a/tools/run_tests/pre_build_node.sh b/tools/run_tests/pre_build_node.sh
index 28ce354f27634ac2354f6e4c6420246dd88aa44a..11f46d60fc243d041b038f9244c389724b443ccc 100755
--- a/tools/run_tests/pre_build_node.sh
+++ b/tools/run_tests/pre_build_node.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
 set -ex
 
+nvm use $NODE_VERSION
+
 export GRPC_CONFIG=${CONFIG:-opt}
 
 # Expire cache after 1 week
diff --git a/tools/run_tests/report_utils.py b/tools/run_tests/report_utils.py
index 35f2069beea7cbea4268bda5d3ad6a89993febac..0032a985232331f51c656626c6e7e8ff9bdd62fb 100644
--- a/tools/run_tests/report_utils.py
+++ b/tools/run_tests/report_utils.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -77,7 +77,7 @@ def render_junit_xml_report(resultset, xml_report):
 
 def render_interop_html_report(
   client_langs, server_langs, test_cases, auth_test_cases, http2_cases, 
-  resultset, num_failures, cloud_to_prod, http2_interop):
+  resultset, num_failures, cloud_to_prod, prod_servers, http2_interop):
   """Generate HTML report for interop tests."""
   template_file = 'tools/run_tests/interop_html_report.template'
   try:
@@ -94,6 +94,7 @@ def render_interop_html_report(
   sorted_http2_cases = sorted(http2_cases)
   sorted_client_langs = sorted(client_langs)
   sorted_server_langs = sorted(server_langs)
+  sorted_prod_servers = sorted(prod_servers)
 
   args = {'client_langs': sorted_client_langs, 
           'server_langs': sorted_server_langs,
@@ -103,6 +104,7 @@ def render_interop_html_report(
           'resultset': resultset,
           'num_failures': num_failures,
           'cloud_to_prod': cloud_to_prod,
+          'prod_servers': sorted_prod_servers,
           'http2_interop': http2_interop}
 
   html_report_out_dir = 'reports' 
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index fbc3b3cdf6fadbc13e798b27ffbe85930019d55e..4a670e0c9db7e55112589b5a22c80e3ac3a1696c 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -422,12 +422,13 @@ def _job_kill_handler(job):
     time.sleep(2)
 
 
-def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False):
+def cloud_to_prod_jobspec(language, test_case, server_host_name, 
+                          server_host_detail, docker_image=None, auth=False):
   """Creates jobspec for cloud-to-prod interop test"""
   container_name = None
   cmdargs = [
-      '--server_host_override=grpc-test.sandbox.googleapis.com',
-      '--server_host=grpc-test.sandbox.googleapis.com',
+      '--server_host=%s' % server_host_detail[0],
+      '--server_host_override=%s' % server_host_detail[1],
       '--server_port=443',
       '--use_tls=true',
       '--test_case=%s' % test_case]
@@ -440,7 +441,8 @@ def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False):
   cwd = language.client_cwd
 
   if docker_image:
-    container_name = dockerjob.random_name('interop_client_%s' % language.safename)
+    container_name = dockerjob.random_name('interop_client_%s' % 
+                                           language.safename)
     cmdline = docker_run_cmdline(cmdline,
                                  image=docker_image,
                                  cwd=cwd,
@@ -455,7 +457,8 @@ def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False):
           cmdline=cmdline,
           cwd=cwd,
           environ=environ,
-          shortname='%s:%s:%s' % (suite_name, language, test_case),
+          shortname='%s:%s:%s:%s' % (suite_name, server_host_name, language, 
+                                     test_case),
           timeout_seconds=90,
           flake_retries=5 if args.allow_flakes else 0,
           timeout_retries=2 if args.allow_flakes else 0,
@@ -491,7 +494,7 @@ def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
           cwd=cwd,
           environ=environ,
           shortname='cloud_to_cloud:%s:%s_server:%s' % (language, server_name,
-                                                 test_case),
+                                                        test_case),
           timeout_seconds=90,
           flake_retries=5 if args.allow_flakes else 0,
           timeout_retries=2 if args.allow_flakes else 0,
@@ -572,6 +575,21 @@ def aggregate_http2_results(stdout):
     'percent': 1.0 * passed / (passed + failed)
   }
 
+# A dictionary of prod servers to test. 
+# Format: server_name: (server_host, server_host_override, errors_allowed)
+# TODO(adelez): implement logic for errors_allowed where if the indicated tests
+# fail, they don't impact the overall test result.
+prod_servers = {
+    'default': ('grpc-test.sandbox.googleapis.com', 
+                'grpc-test.sandbox.googleapis.com', False),
+    'gateway_v2': ('grpc-test2.sandbox.googleapis.com', 
+                   'grpc-test2.sandbox.googleapis.com', True),
+    'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com', 
+                      False),
+    'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com', 
+                         True)
+}
+
 argp = argparse.ArgumentParser(description='Run interop tests.')
 argp.add_argument('-l', '--language',
                   choices=['all'] + sorted(_LANGUAGES),
@@ -589,6 +607,12 @@ argp.add_argument('--cloud_to_prod_auth',
                   action='store_const',
                   const=True,
                   help='Run cloud_to_prod_auth tests.')
+argp.add_argument('--prod_servers',
+                  choices=prod_servers.keys(),
+                  default=['default'],
+                  nargs='+',
+                  help=('The servers to run cloud_to_prod and '
+                        'cloud_to_prod_auth tests against.'))
 argp.add_argument('-s', '--server',
                   choices=['all'] + sorted(_SERVERS),
                   action='append',
@@ -688,32 +712,37 @@ try:
     server_jobs[lang] = job
     server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
 
-
   jobs = []
   if args.cloud_to_prod:
-    for language in languages:
-      for test_case in _TEST_CASES:
-        if not test_case in language.unimplemented_test_cases():
-          if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
-            test_job = cloud_to_prod_jobspec(language, test_case,
-                                             docker_image=docker_images.get(str(language)))
-            jobs.append(test_job)
-
-    if args.http2_interop:
-      for test_case in _HTTP2_TEST_CASES:
-        test_job = cloud_to_prod_jobspec(http2Interop, test_case,
-                                         docker_image=docker_images.get(str(http2Interop)))
-        jobs.append(test_job)
-
+    for server_host_name in args.prod_servers:
+      for language in languages:
+        for test_case in _TEST_CASES:
+          if not test_case in language.unimplemented_test_cases():
+            if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
+              test_job = cloud_to_prod_jobspec(
+                  language, test_case, server_host_name, 
+                  prod_servers[server_host_name],
+                  docker_image=docker_images.get(str(language)))
+              jobs.append(test_job)
+
+      if args.http2_interop:
+        for test_case in _HTTP2_TEST_CASES:
+          test_job = cloud_to_prod_jobspec(
+              http2Interop, test_case, server_host_name, 
+              prod_servers[server_host_name],
+              docker_image=docker_images.get(str(http2Interop)))
+          jobs.append(test_job)
 
   if args.cloud_to_prod_auth:
-    for language in languages:
-      for test_case in _AUTH_TEST_CASES:
-        if not test_case in language.unimplemented_test_cases():
-          test_job = cloud_to_prod_jobspec(language, test_case,
-                                           docker_image=docker_images.get(str(language)),
-                                           auth=True)
-          jobs.append(test_job)
+    for server_host_name in args.prod_servers:
+      for language in languages:
+        for test_case in _AUTH_TEST_CASES:
+          if not test_case in language.unimplemented_test_cases():
+            test_job = cloud_to_prod_jobspec(
+                language, test_case, server_host_name, 
+                prod_servers[server_host_name],
+                docker_image=docker_images.get(str(language)), auth=True)
+            jobs.append(test_job)
 
   for server in args.override_server:
     server_name = server[0]
@@ -773,7 +802,8 @@ try:
   report_utils.render_interop_html_report(
       set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
       _HTTP2_TEST_CASES, resultset, num_failures,
-      args.cloud_to_prod_auth or args.cloud_to_prod, args.http2_interop)
+      args.cloud_to_prod_auth or args.cloud_to_prod, args.prod_servers, 
+      args.http2_interop)
 
 finally:
   # Check if servers are still running.
diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh
index f93c9c30cbef5c022317870c7dd46320dde4db9f..40f61d77cc9bec232d2a5337ca4d0bdddb9de107 100755
--- a/tools/run_tests/run_node.sh
+++ b/tools/run_tests/run_node.sh
@@ -28,8 +28,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
 set -ex
 
+nvm use $NODE_VERSION
+
 CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 9e7b97c6a212b3e4e68da6e6ef42dd0696246df3..6dfdc705bec0e6ca3bdb1042d3336b90b8d4a2ee 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -194,13 +194,17 @@ class CLanguage(object):
 
 class NodeLanguage(object):
 
+  def __init__(self):
+    self.node_version = '0.12'
+
   def test_specs(self, config, args):
-    return [config.job_spec(['tools/run_tests/run_node.sh'], None,
+    return [config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
+                            None,
                             environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def pre_build_steps(self):
     # Default to 1 week cache expiration
-    return [['tools/run_tests/pre_build_node.sh']]
+    return [['tools/run_tests/pre_build_node.sh', self.node_version]]
 
   def make_targets(self, test_regex):
     return []
@@ -209,7 +213,7 @@ class NodeLanguage(object):
     return []
 
   def build_steps(self):
-    return [['tools/run_tests/build_node.sh']]
+    return [['tools/run_tests/build_node.sh', self.node_version]]
 
   def post_tests_steps(self):
     return []