THRIFT-3347 Improve cross test servers and clients
Client: TestSuite, C++, Perl, NodeJS, c_glib, Haskell, Python
Patch: Nobuaki Sukegawa <nsukeg@gmail.com>

This closes #621
diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp
index 1c0254b..7c425a9 100644
--- a/test/cpp/src/TestClient.cpp
+++ b/test/cpp/src/TestClient.cpp
@@ -266,7 +266,12 @@
   uint64_t time_max = 0;
   uint64_t time_tot = 0;
 
-  int failCount = 0;
+  int return_code = 0;
+  int ERR_BASETYPES = 1;
+  int ERR_STRUCTS = 2;
+  int ERR_CONTAINERS = 4;
+  int ERR_EXCEPTIONS = 8;
+
   int test = 0;
   for (test = 0; test < numTests; ++test) {
 
@@ -292,8 +297,9 @@
       testClient.testVoid();
       printf(" = void\n");
     } catch (TApplicationException& tax) {
+      printf("*** FAILED ***\n");
       printf("%s\n", tax.what());
-      failCount++;
+      return_code |= ERR_BASETYPES;
     }
 
     /**
@@ -303,8 +309,10 @@
     string s;
     testClient.testString(s, "Test");
     printf(" = \"%s\"\n", s.c_str());
-    if (s != "Test")
-      failCount++;
+    if (s != "Test") {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * BOOL TEST
@@ -312,14 +320,18 @@
     printf("testBool(true)");
     bool bl = testClient.testBool(true);
     printf(" = %s\n", bl ? "true" : "false");
-    if (bl != true)
-      failCount++;
+    if (bl != true) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     printf("testBool(false)");
     bl = testClient.testBool(false);
     printf(" = %s\n", bl ? "true" : "false");
-    if (bl != false)
-      failCount++;
+    if (bl != false) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * BYTE TEST
@@ -327,8 +339,10 @@
     printf("testByte(1)");
     uint8_t u8 = testClient.testByte(1);
     printf(" = %d\n", (int)u8);
-    if (u8 != 1)
-      failCount++;
+    if (u8 != 1) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * I32 TEST
@@ -336,8 +350,10 @@
     printf("testI32(-1)");
     int32_t i32 = testClient.testI32(-1);
     printf(" = %d\n", i32);
-    if (i32 != -1)
-      failCount++;
+    if (i32 != -1) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * I64 TEST
@@ -345,8 +361,10 @@
     printf("testI64(-34359738368)");
     int64_t i64 = testClient.testI64(-34359738368LL);
     printf(" = %" PRId64 "\n", i64);
-    if (i64 != -34359738368LL)
-      failCount++;
+    if (i64 != -34359738368LL) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * DOUBLE TEST
@@ -354,13 +372,66 @@
     printf("testDouble(-5.2098523)");
     double dub = testClient.testDouble(-5.2098523);
     printf(" = %f\n", dub);
-    if ((dub - (-5.2098523)) > 0.001)
-      failCount++;
+    if ((dub - (-5.2098523)) > 0.001) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * BINARY TEST
      */
-    // TODO: add testBinary() call
+    printf("testBinary([-128..127]) = {");
+    const char bin_data[256]
+        = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114,
+           -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99,
+           -98,  -97,  -96,  -95,  -94,  -93,  -92,  -91,  -90,  -89,  -88,  -87,  -86,  -85,  -84,
+           -83,  -82,  -81,  -80,  -79,  -78,  -77,  -76,  -75,  -74,  -73,  -72,  -71,  -70,  -69,
+           -68,  -67,  -66,  -65,  -64,  -63,  -62,  -61,  -60,  -59,  -58,  -57,  -56,  -55,  -54,
+           -53,  -52,  -51,  -50,  -49,  -48,  -47,  -46,  -45,  -44,  -43,  -42,  -41,  -40,  -39,
+           -38,  -37,  -36,  -35,  -34,  -33,  -32,  -31,  -30,  -29,  -28,  -27,  -26,  -25,  -24,
+           -23,  -22,  -21,  -20,  -19,  -18,  -17,  -16,  -15,  -14,  -13,  -12,  -11,  -10,  -9,
+           -8,   -7,   -6,   -5,   -4,   -3,   -2,   -1,   0,    1,    2,    3,    4,    5,    6,
+           7,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,
+           22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,
+           37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,
+           52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,   65,   66,
+           67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
+           82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,   96,
+           97,   98,   99,   100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
+           112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126,
+           127};
+    try {
+      string bin_result;
+      testClient.testBinary(bin_result, string(bin_data, 256));
+      if (bin_result.size() != 256) {
+        printf("}\n*** FAILED ***\n");
+        printf("invalid length: %lu\n", bin_result.size());
+        return_code |= ERR_BASETYPES;
+      } else {
+        bool first = true;
+        bool failed = false;
+        for (int i = 0; i < 256; ++i) {
+          if (!first)
+            printf(" ,");
+          else
+            first = false;
+          printf("%d", bin_result[i]);
+          if (!failed && bin_result[i] != i - 128) {
+            failed = true;
+          }
+        }
+        printf("}\n");
+        if (failed) {
+          printf("*** FAILED ***\n");
+          return_code |= ERR_BASETYPES;
+        }
+      }
+    } catch (exception& ex) {
+      printf("}\n*** FAILED ***\n");
+      printf("%s\n", ex.what());
+      return_code |= ERR_BASETYPES;
+    }
+
 
     /**
      * STRUCT TEST
@@ -378,8 +449,10 @@
            (int)in.byte_thing,
            in.i32_thing,
            in.i64_thing);
-    if (in != out)
-      failCount++;
+    if (in != out) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * NESTED STRUCT TEST
@@ -399,8 +472,10 @@
            in.i32_thing,
            in.i64_thing,
            in2.i32_thing);
-    if (in2 != out2)
-      failCount++;
+    if (in2 != out2) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * MAP TEST
@@ -434,13 +509,40 @@
       printf("%d => %d", m_iter->first, m_iter->second);
     }
     printf("}\n");
-    if (mapin != mapout)
-      failCount++;
+    if (mapin != mapout) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * STRING MAP TEST
-     *  missing
      */
+    printf("testStringMap({a => 2, b => blah, some => thing}) = {");
+    map<string, string> smapin;
+    map<string, string> smapout;
+    smapin["a"] = "2";
+    smapin["b"] = "blah";
+    smapin["some"] = "thing";
+    try {
+      testClient.testStringMap(smapout, smapin);
+      first = true;
+      for (map<string, string>::const_iterator it = smapout.begin(); it != smapout.end(); ++it) {
+        if (first)
+          printf(",");
+        else
+          first = false;
+        printf("%s => %s", it->first.c_str(), it->second.c_str());
+      }
+      printf("}\n");
+      if (smapin != smapout) {
+        printf("*** FAILED ***\n");
+        return_code |= ERR_CONTAINERS;
+      }
+    } catch (exception& ex) {
+      printf("}\n*** FAILED ***\n");
+      printf("%s\n", ex.what());
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * SET TEST
@@ -474,8 +576,10 @@
       printf("%d", *s_iter);
     }
     printf("}\n");
-    if (setin != setout)
-      failCount++;
+    if (setin != setout) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * LIST TEST
@@ -509,8 +613,10 @@
       printf("%d", *l_iter);
     }
     printf("}\n");
-    if (listin != listout)
-      failCount++;
+    if (listin != listout) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * ENUM TEST
@@ -518,32 +624,42 @@
     printf("testEnum(ONE)");
     Numberz::type ret = testClient.testEnum(Numberz::ONE);
     printf(" = %d\n", ret);
-    if (ret != Numberz::ONE)
-      failCount++;
+    if (ret != Numberz::ONE) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     printf("testEnum(TWO)");
     ret = testClient.testEnum(Numberz::TWO);
     printf(" = %d\n", ret);
-    if (ret != Numberz::TWO)
-      failCount++;
+    if (ret != Numberz::TWO) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     printf("testEnum(THREE)");
     ret = testClient.testEnum(Numberz::THREE);
     printf(" = %d\n", ret);
-    if (ret != Numberz::THREE)
-      failCount++;
+    if (ret != Numberz::THREE) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     printf("testEnum(FIVE)");
     ret = testClient.testEnum(Numberz::FIVE);
     printf(" = %d\n", ret);
-    if (ret != Numberz::FIVE)
-      failCount++;
+    if (ret != Numberz::FIVE) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     printf("testEnum(EIGHT)");
     ret = testClient.testEnum(Numberz::EIGHT);
     printf(" = %d\n", ret);
-    if (ret != Numberz::EIGHT)
-      failCount++;
+    if (ret != Numberz::EIGHT) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * TYPEDEF TEST
@@ -551,8 +667,10 @@
     printf("testTypedef(309858235082523)");
     UserId uid = testClient.testTypedef(309858235082523LL);
     printf(" = %" PRId64 "\n", uid);
-    if (uid != 309858235082523LL)
-      failCount++;
+    if (uid != 309858235082523LL) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * NESTED MAP TEST
@@ -571,19 +689,38 @@
       printf("}, ");
     }
     printf("}\n");
+    if (mm.size() != 2 ||
+        mm[-4][-4] != -4 ||
+        mm[-4][-3] != -3 ||
+        mm[-4][-2] != -2 ||
+        mm[-4][-1] != -1 ||
+        mm[4][4] != 4 ||
+        mm[4][3] != 3 ||
+        mm[4][2] != 2 ||
+        mm[4][1] != 1) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * INSANITY TEST
      */
     if (!noinsane) {
       Insanity insane;
-      insane.userMap.insert(make_pair(Numberz::FIVE, 5000));
+      insane.userMap.insert(make_pair(Numberz::FIVE, 5));
+      insane.userMap.insert(make_pair(Numberz::EIGHT, 8));
       Xtruct truck;
-      truck.string_thing = "Truck";
-      truck.byte_thing = 8;
-      truck.i32_thing = 8;
-      truck.i64_thing = 8;
+      truck.string_thing = "Goodbye4";
+      truck.byte_thing = 4;
+      truck.i32_thing = 4;
+      truck.i64_thing = 4;
+      Xtruct truck2;
+      truck2.string_thing = "Hello2";
+      truck2.byte_thing = 2;
+      truck2.i32_thing = 2;
+      truck2.i64_thing = 2;
       insane.xtructs.push_back(truck);
+      insane.xtructs.push_back(truck2);
       printf("testInsanity()");
       map<UserId, map<Numberz::type, Insanity> > whoa;
       testClient.testInsanity(whoa, insane);
@@ -619,14 +756,69 @@
         printf("}, ");
       }
       printf("}\n");
+      bool failed = false;
+      map<UserId, map<Numberz::type, Insanity> >::const_iterator it1 = whoa.find(UserId(1));
+      if (whoa.size() != 2) {
+        failed = true;
+      }
+      if (it1 == whoa.end()) {
+        failed = true;
+      } else {
+        map<Numberz::type, Insanity>::const_iterator it12 = it1->second.find(Numberz::TWO);
+        if (it12 == it1->second.end() || it12->second != insane) {
+          failed = true;
+        }
+        map<Numberz::type, Insanity>::const_iterator it13 = it1->second.find(Numberz::THREE);
+        if (it13 == it1->second.end() || it13->second != insane) {
+          failed = true;
+        }
+      }
+      map<UserId, map<Numberz::type, Insanity> >::const_iterator it2 = whoa.find(UserId(2));
+      if (it2 == whoa.end()) {
+        failed = true;
+      } else {
+        map<Numberz::type, Insanity>::const_iterator it26 = it2->second.find(Numberz::SIX);
+        if (it26 == it1->second.end() || it26->second != Insanity()) {
+          failed = true;
+        }
+      }
+      if (failed) {
+        printf("*** FAILED ***\n");
+        return_code |= ERR_STRUCTS;
+      }
     }
+
+    /**
+     * MULTI TEST
+     */
+    printf("testMulti()\n");
+    try {
+      map<int16_t, string> mul_map;
+      Xtruct mul_result;
+      mul_map[1] = "blah";
+      mul_map[2] = "thing";
+      testClient.testMulti(mul_result, 42, 4242, 424242, mul_map, Numberz::EIGHT, UserId(24));
+      Xtruct xxs;
+      xxs.string_thing = "Hello2";
+      xxs.byte_thing = 42;
+      xxs.i32_thing = 4242;
+      xxs.i64_thing = 424242;
+      if (mul_result != xxs) {
+        printf("*** FAILED ***\n");
+        return_code |= ERR_STRUCTS;
+      }
+    } catch (exception& ex) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
+
     /* test exception */
 
     try {
       printf("testClient.testException(\"Xception\") =>");
       testClient.testException("Xception");
-      printf("  void\nFAILURE\n");
-      failCount++;
+      printf("  void\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
 
     } catch (Xception& e) {
       printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
@@ -635,8 +827,8 @@
     try {
       printf("testClient.testException(\"TException\") =>");
       testClient.testException("TException");
-      printf("  void\nFAILURE\n");
-      failCount++;
+      printf("  void\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
 
     } catch (const TException&) {
       printf("  Caught TException\n");
@@ -647,8 +839,8 @@
       testClient.testException("success");
       printf("  void\n");
     } catch (...) {
-      printf("  exception\nFAILURE\n");
-      failCount++;
+      printf("  exception\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
     }
 
     /* test multi exception */
@@ -657,8 +849,8 @@
       printf("testClient.testMultiException(\"Xception\", \"test 1\") =>");
       Xtruct result;
       testClient.testMultiException(result, "Xception", "test 1");
-      printf("  result\nFAILURE\n");
-      failCount++;
+      printf("  result\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
     } catch (Xception& e) {
       printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
     }
@@ -667,8 +859,8 @@
       printf("testClient.testMultiException(\"Xception2\", \"test 2\") =>");
       Xtruct result;
       testClient.testMultiException(result, "Xception2", "test 2");
-      printf("  result\nFAILURE\n");
-      failCount++;
+      printf("  result\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
 
     } catch (Xception2& e) {
       printf("  {%u, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing.c_str());
@@ -680,8 +872,8 @@
       testClient.testMultiException(result, "success", "test 3");
       printf("  {{\"%s\"}}\n", result.string_thing.c_str());
     } catch (...) {
-      printf("  exception\nFAILURE\n");
-      failCount++;
+      printf("  exception\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
     }
 
     /* test oneway void */
@@ -691,8 +883,8 @@
       testClient.testOneway(1);
       uint64_t elapsed = now() - startOneway;
       if (elapsed > 200 * 1000) { // 0.2 seconds
-        printf("  FAILURE - took %.2f ms\n", (double)elapsed / 1000.0);
-        failCount++;
+        printf("*** FAILED *** - took %.2f ms\n", (double)elapsed / 1000.0);
+      return_code |= ERR_BASETYPES;
       } else {
         printf("  success - took %.2f ms\n", (double)elapsed / 1000.0);
       }
@@ -713,7 +905,7 @@
     i32 = testClient.testI32(-1);
     printf(" = %d\n", i32);
     if (i32 != -1)
-      failCount++;
+      return_code |= ERR_BASETYPES;
 
     uint64_t stop = now();
     uint64_t tot = stop - start;
@@ -739,5 +931,5 @@
   printf("Max time: %" PRIu64 " us\n", time_max);
   printf("Avg time: %" PRIu64 " us\n", time_avg);
 
-  return failCount;
+  return return_code;
 }
diff --git a/test/hs/TestClient.hs b/test/hs/TestClient.hs
index 6c25f5b..057a560 100644
--- a/test/hs/TestClient.hs
+++ b/test/hs/TestClient.hs
@@ -26,19 +26,24 @@
 import Data.List.Split
 import Data.String
 import Network
+import Network.URI
 import System.Environment
 import System.Exit
 import System.Posix.Unistd
+import qualified Data.ByteString.Lazy as LBS
 import qualified Data.HashMap.Strict as Map
 import qualified Data.HashSet as Set
 import qualified Data.Vector as Vector
+import qualified System.IO as IO
 
 import ThriftTest_Iface
 import ThriftTest_Types
 import qualified ThriftTest_Client as Client
 
 import Thrift.Transport
+import Thrift.Transport.Framed
 import Thrift.Transport.Handle
+import Thrift.Transport.HttpClient
 import Thrift.Protocol
 import Thrift.Protocol.Binary
 import Thrift.Protocol.Compact
@@ -50,11 +55,34 @@
   , domainSocket :: String
   , transport    :: String
   , protocol     :: ProtocolType
+  -- TODO: Haskell lib does not have SSL support
   , ssl          :: Bool
   , testLoops    :: Int
   }
   deriving (Show, Eq)
 
+data TransportType = Buffered IO.Handle
+                   | Framed (FramedTransport IO.Handle)
+                   | Http HttpClient
+                   | NoTransport String
+
+getTransport :: String -> String -> Int -> (IO TransportType)
+getTransport "buffered" host port = do
+  h <- hOpen (host, PortNumber $ fromIntegral port)
+  IO.hSetBuffering h $ IO.BlockBuffering Nothing
+  return $ Buffered h
+getTransport "framed" host port = do
+  h <- hOpen (host, PortNumber $ fromIntegral port)
+  t <- openFramedTransport h
+  return $ Framed t
+getTransport "http" host port = let uriStr = "http://" ++ host ++ ":" ++ show port in
+                                case parseURI uriStr of
+                                  Nothing -> do return (NoTransport $ "Failed to parse URI: " ++ uriStr)
+                                  Just(uri) -> do
+                                    t <- openHttpClient uri
+                                    return $ Http t
+getTransport t host port = do return (NoTransport $ "Unsupported transport: " ++ t)
+
 data ProtocolType = Binary
                   | Compact
                   | JSON
@@ -71,7 +99,7 @@
   { port         = 9090
   , domainSocket = ""
   , host         = "localhost"
-  , transport    = "framed"
+  , transport    = "buffered"
   , protocol     = Binary
   , ssl          = False
   , testLoops    = 1
@@ -83,29 +111,46 @@
   putStrLn "Starting Tests"
 
   -- VOID Test
+  putStrLn "testVoid"
   Client.testVoid prot
 
   -- String Test
+  putStrLn "testString"
   s <- Client.testString prot "Test"
   when (s /= "Test") exitFailure
 
+  -- Bool Test
+  putStrLn "testBool"
+  bool <- Client.testBool prot True
+  when (not bool) exitFailure
+  putStrLn "testBool"
+  bool <- Client.testBool prot False
+  when (bool) exitFailure
+
   -- Byte Test
+  putStrLn "testByte"
   byte <- Client.testByte prot 1
   when (byte /= 1) exitFailure
 
   -- I32 Test
+  putStrLn "testI32"
   i32 <- Client.testI32 prot (-1)
   when (i32 /= -1) exitFailure
 
   -- I64 Test
+  putStrLn "testI64"
   i64 <- Client.testI64 prot (-34359738368)
   when (i64 /= -34359738368) exitFailure
 
   -- Double Test
+  putStrLn "testDouble"
   dub <- Client.testDouble prot (-5.2098523)
   when (abs (dub + 5.2098523) > 0.001) exitFailure
 
-  -- TODO: call Client.testBinary
+  -- Binary Test
+  putStrLn "testBinary"
+  bin <- Client.testBinary prot (LBS.pack . reverse $ [-128..127])
+  when ((reverse [-128..127]) /= LBS.unpack bin) exitFailure
   
   -- Struct Test
   let structIn = Xtruct{ xtruct_string_thing = "Zero"
@@ -113,6 +158,7 @@
                        , xtruct_i32_thing    = -3
                        , xtruct_i64_thing    = -5
                        }
+  putStrLn "testStruct"
   structOut <- Client.testStruct prot structIn
   when (structIn /= structOut) exitFailure
 
@@ -121,68 +167,83 @@
                       , xtruct2_struct_thing = structIn
                       , xtruct2_i32_thing    = 5
                       }
+  putStrLn "testNest"
   nestOut <- Client.testNest prot nestIn
   when (nestIn /= nestOut) exitSuccess
 
   -- Map Test
   let mapIn = Map.fromList $ map (\i -> (i, i-10)) [1..5]
+  putStrLn "testMap"
   mapOut <- Client.testMap prot mapIn
   when (mapIn /= mapOut) exitSuccess
 
   -- Set Test
   let setIn = Set.fromList [-2..3]
+  putStrLn "testSet"
   setOut <- Client.testSet prot setIn
   when (setIn /= setOut) exitFailure
 
   -- List Test
   let listIn = Vector.fromList [-2..3]
+  putStrLn "testList"
   listOut <- Client.testList prot listIn
   when (listIn /= listOut) exitFailure
 
   -- Enum Test
+  putStrLn "testEnum"
   numz1 <- Client.testEnum prot ONE
   when (numz1 /= ONE) exitFailure
 
+  putStrLn "testEnum"
   numz2 <- Client.testEnum prot TWO
   when (numz2 /= TWO) exitFailure
 
+  putStrLn "testEnum"
   numz5 <- Client.testEnum prot FIVE
   when (numz5 /= FIVE) exitFailure
 
   -- Typedef Test
+  putStrLn "testTypedef"
   uid <- Client.testTypedef prot 309858235082523
   when (uid /= 309858235082523) exitFailure
 
   -- Nested Map Test
+  putStrLn "testMapMap"
   _ <- Client.testMapMap prot 1
 
   -- Exception Test
+  putStrLn "testException"
   exn1 <- try $ Client.testException prot "Xception"
   case exn1 of
     Left (Xception _ _) -> return ()
     _ -> putStrLn (show exn1) >> exitFailure
 
+  putStrLn "testException"
   exn2 <- try $ Client.testException prot "TException"
   case exn2 of
     Left (_ :: SomeException) -> return ()
     Right _ -> exitFailure
 
+  putStrLn "testException"
   exn3 <- try $ Client.testException prot "success"
   case exn3 of
     Left (_ :: SomeException) -> exitFailure
     Right _ -> return ()
 
   -- Multi Exception Test
+  putStrLn "testMultiException"
   multi1 <- try $ Client.testMultiException prot "Xception" "test 1"
   case multi1 of
     Left (Xception _ _) -> return ()
     _ -> exitFailure
 
+  putStrLn "testMultiException"
   multi2 <- try $ Client.testMultiException prot "Xception2" "test 2"
   case multi2 of
     Left (Xception2 _ _) -> return ()
     _ -> exitFailure
 
+  putStrLn "testMultiException"
   multi3 <- try $ Client.testMultiException prot "success" "test 3"
   case multi3 of
     Left (_ :: SomeException) -> exitFailure
@@ -195,12 +256,20 @@
   case options of
     Nothing -> showHelp
     Just Options{..} -> do
-      handle <- hOpen (host, PortNumber $ fromIntegral port)
-      let client = case protocol of
-            Binary  -> runClient $ BinaryProtocol handle
-            Compact -> runClient $ CompactProtocol handle
-            JSON    -> runClient $ JSONProtocol handle
-      replicateM_ testLoops client
+      trans <- Main.getTransport transport host port
+      case trans of
+        Buffered t -> runTest testLoops protocol t
+        Framed t   -> runTest testLoops protocol t
+        Http t     -> runTest testLoops protocol t
+        NoTransport err -> putStrLn err
+  where
+    makeClient p t = case p of
+                       Binary  -> runClient $ BinaryProtocol t
+                       Compact -> runClient $ CompactProtocol t
+                       JSON    -> runClient $ JSONProtocol t
+    runTest loops p t = do
+      let client = makeClient p t
+      replicateM_ loops client
       putStrLn "COMPLETED SUCCESSFULLY"
 
 parseFlags :: [String] -> Options -> Maybe Options
@@ -228,7 +297,7 @@
   \  --port arg (=9090)          Port number to connect\n\
   \  --domain-socket arg         Domain Socket (e.g. /tmp/ThriftTest.thrift),\n\
   \                              instead of host and port\n\
-  \  --transport arg (=buffered) Transport: buffered, framed, http, evhttp\n\
+  \  --transport arg (=buffered) Transport: buffered, framed, http\n\
   \  --protocol arg (=binary)    Protocol: binary, compact, json\n\
   \  --ssl                       Encrypted Transport using SSL\n\
-  \  -n [ --testloops ] arg (=1) Number of Tests"
\ No newline at end of file
+  \  -n [ --testloops ] arg (=1) Number of Tests"
diff --git a/test/hs/TestServer.hs b/test/hs/TestServer.hs
index fb80cf8..a880a5e 100755
--- a/test/hs/TestServer.hs
+++ b/test/hs/TestServer.hs
@@ -32,6 +32,7 @@
 import System.Exit
 import System.IO
 import System.Posix.Unistd
+import qualified System.IO as IO
 import qualified Data.HashMap.Strict as Map
 import qualified Data.HashSet as Set
 import qualified Data.Text.Lazy as Text
@@ -72,6 +73,20 @@
   fromString "nonblocking" = NonBlocking
   fromString _ = error "not a valid server type"
 
+data TransportType = Buffered (Socket -> (IO IO.Handle))
+                   | Framed (Socket -> (IO (FramedTransport IO.Handle)))
+                   | NoTransport String
+
+getTransport :: String -> TransportType
+getTransport "buffered" = Buffered $ \s -> do
+  (h, _, _) <- (accept s)
+  IO.hSetBuffering h $ IO.BlockBuffering Nothing
+  return h
+getTransport "framed" = Framed $ \s -> do
+  (h, _, _) <- (accept s)
+  openFramedTransport h
+getTransport t = NoTransport $ "Unsupported transport: " ++ t
+
 data ProtocolType = Binary
                   | Compact
                   | JSON
@@ -87,8 +102,9 @@
   { port         = 9090
   , domainSocket = ""
   , serverType   = Threaded
-  , transport    = "framed"
+  , transport    = "buffered"
   , protocol     = Binary
+  -- TODO: Haskell lib does not have SSL support
   , ssl          = False
   , workers      = 4
   }
@@ -234,17 +250,24 @@
   case options of
     Nothing -> showHelp
     Just Options{..} -> do
+      case Main.getTransport transport of
+        Buffered f -> runServer protocol f port
+        Framed   f -> runServer protocol f port
+        NoTransport err -> putStrLn err
       System.IO.putStrLn $ "Starting \"" ++ show serverType ++ "\" server (" ++
         show transport ++ ") listen on: " ++ domainSocket ++ show port
-      case protocol of
-        Binary  -> runServer BinaryProtocol port
-        Compact -> runServer CompactProtocol port
-        JSON    -> runServer JSONProtocol port
       where
-        runServer p = runThreadedServer (accepter p) TestHandler ThriftTest.process . PortNumber . fromIntegral
-        accepter p s = do
-          (h, _, _) <- accept s
-          return (p h, p h)
+        acceptor p f socket = do
+          t <- f socket
+          return (p t, p t)
+
+        doRunServer p f = do
+          runThreadedServer (acceptor p f) TestHandler ThriftTest.process . PortNumber . fromIntegral
+
+        runServer p f port = case p of
+          Binary  -> do doRunServer BinaryProtocol f port
+          Compact -> do doRunServer CompactProtocol f port
+          JSON    -> do doRunServer JSONProtocol f port
 
 parseFlags :: [String] -> Options -> Maybe Options
 parseFlags (flag : flags) opts = do
@@ -272,9 +295,9 @@
   \  --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)\n\
   \  --server-type arg (=simple) type of server, \"simple\", \"thread-pool\",\n\
   \                              \"threaded\", or \"nonblocking\"\n\
-  \  --transport arg (=buffered) transport: buffered, framed, http\n\
+  \  --transport arg (=buffered) transport: buffered, framed\n\
   \  --protocol arg (=binary)    protocol: binary, compact, json\n\
   \  --ssl                       Encrypted Transport using SSL\n\
   \  --processor-events          processor-events\n\
   \  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for\n\
-  \                              thread-pool server type"
\ No newline at end of file
+  \                              thread-pool server type"
diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json
index bf05f93..ee12ebf 100644
--- a/test/known_failures_Linux.json
+++ b/test/known_failures_Linux.json
@@ -1,6 +1,9 @@
 [
+  "c_glib-cpp_binary_buffered-ip",
+  "c_glib-cpp_binary_framed-ip",
   "c_glib-csharp_binary_buffered-ip",
   "c_glib-csharp_binary_framed-ip",
+  "c_glib-hs_binary_buffered-ip",
   "c_glib-hs_binary_framed-ip",
   "c_glib-nodejs_binary_buffered-ip",
   "c_glib-nodejs_binary_framed-ip",
@@ -12,11 +15,8 @@
   "c_glib-rb_binary-accel_framed-ip",
   "c_glib-rb_binary_buffered-ip",
   "c_glib-rb_binary_framed-ip",
-  "cpp-cpp_binary_http-domain",
   "cpp-cpp_binary_http-ip",
   "cpp-cpp_compact_http-domain",
-  "cpp-cpp_compact_http-ip",
-  "cpp-cpp_json_http-domain",
   "cpp-cpp_json_http-ip",
   "cpp-csharp_binary_buffered-ip-ssl",
   "cpp-csharp_binary_framed-ip-ssl",
@@ -24,27 +24,9 @@
   "cpp-csharp_compact_framed-ip-ssl",
   "cpp-csharp_json_buffered-ip-ssl",
   "cpp-csharp_json_framed-ip-ssl",
-  "cpp-hs_binary_buffered-ip-ssl",
-  "cpp-hs_binary_framed-ip",
-  "cpp-hs_binary_framed-ip-ssl",
-  "cpp-hs_binary_http-evhttp-ip",
-  "cpp-hs_binary_http-evhttp-ip-ssl",
-  "cpp-hs_binary_http-ip",
-  "cpp-hs_binary_http-ip-ssl",
-  "cpp-hs_compact_buffered-ip-ssl",
-  "cpp-hs_compact_framed-ip",
-  "cpp-hs_compact_framed-ip-ssl",
-  "cpp-hs_compact_http-evhttp-ip",
-  "cpp-hs_compact_http-evhttp-ip-ssl",
-  "cpp-hs_compact_http-ip",
-  "cpp-hs_compact_http-ip-ssl",
-  "cpp-hs_json_buffered-ip-ssl",
+  "cpp-hs_json_buffered-ip",
   "cpp-hs_json_framed-ip",
-  "cpp-hs_json_framed-ip-ssl",
-  "cpp-hs_json_http-evhttp-ip",
-  "cpp-hs_json_http-evhttp-ip-ssl",
   "cpp-hs_json_http-ip",
-  "cpp-hs_json_http-ip-ssl",
   "cpp-java_binary_http-ip",
   "cpp-java_binary_http-ip-ssl",
   "cpp-java_compact_http-ip",
@@ -92,17 +74,11 @@
   "csharp-go_json_framed-ip",
   "csharp-go_json_framed-ip-ssl",
   "csharp-hs_binary_buffered-ip",
-  "csharp-hs_binary_buffered-ip-ssl",
   "csharp-hs_binary_framed-ip",
-  "csharp-hs_binary_framed-ip-ssl",
   "csharp-hs_compact_buffered-ip",
-  "csharp-hs_compact_buffered-ip-ssl",
   "csharp-hs_compact_framed-ip",
-  "csharp-hs_compact_framed-ip-ssl",
   "csharp-hs_json_buffered-ip",
-  "csharp-hs_json_buffered-ip-ssl",
   "csharp-hs_json_framed-ip",
-  "csharp-hs_json_framed-ip-ssl",
   "csharp-java_binary_buffered-ip",
   "csharp-java_binary_buffered-ip-ssl",
   "csharp-java_binary_framed-fastframed-ip",
@@ -151,21 +127,18 @@
   "csharp-rb_json_framed-ip",
   "go-c_glib_binary_buffered-ip",
   "go-c_glib_binary_framed-ip",
+  "go-cpp_json_buffered-ip",
+  "go-cpp_json_buffered-ip-ssl",
+  "go-cpp_json_framed-ip",
+  "go-cpp_json_framed-ip-ssl",
   "go-csharp_binary_buffered-ip-ssl",
   "go-csharp_binary_framed-ip-ssl",
   "go-csharp_compact_buffered-ip-ssl",
   "go-csharp_compact_framed-ip-ssl",
   "go-csharp_json_buffered-ip-ssl",
   "go-csharp_json_framed-ip-ssl",
-  "go-hs_binary_buffered-ip-ssl",
-  "go-hs_binary_framed-ip",
-  "go-hs_binary_framed-ip-ssl",
-  "go-hs_compact_buffered-ip-ssl",
-  "go-hs_compact_framed-ip",
-  "go-hs_compact_framed-ip-ssl",
-  "go-hs_json_buffered-ip-ssl",
+  "go-hs_json_buffered-ip",
   "go-hs_json_framed-ip",
-  "go-hs_json_framed-ip-ssl",
   "go-nodejs_binary_buffered-ip",
   "go-nodejs_binary_buffered-ip-ssl",
   "go-nodejs_binary_framed-ip",
@@ -182,111 +155,26 @@
   "go-perl_binary_framed-ip-ssl",
   "go-rb_json_buffered-ip",
   "go-rb_json_framed-ip",
-  "hs-c_glib_binary_buffered-ip",
-  "hs-c_glib_binary_framed-ip",
-  "hs-cpp_binary_buffered-ip-ssl",
-  "hs-cpp_binary_evhttp-http-ip",
-  "hs-cpp_binary_evhttp-http-ip-ssl",
-  "hs-cpp_binary_framed-ip",
-  "hs-cpp_binary_framed-ip-ssl",
-  "hs-cpp_binary_http-ip",
-  "hs-cpp_binary_http-ip-ssl",
-  "hs-cpp_compact_buffered-ip-ssl",
-  "hs-cpp_compact_evhttp-http-ip",
-  "hs-cpp_compact_evhttp-http-ip-ssl",
-  "hs-cpp_compact_framed-ip",
-  "hs-cpp_compact_framed-ip-ssl",
-  "hs-cpp_compact_http-ip",
-  "hs-cpp_compact_http-ip-ssl",
   "hs-cpp_json_buffered-ip",
-  "hs-cpp_json_buffered-ip-ssl",
-  "hs-cpp_json_evhttp-http-ip",
-  "hs-cpp_json_evhttp-http-ip-ssl",
   "hs-cpp_json_framed-ip",
-  "hs-cpp_json_framed-ip-ssl",
-  "hs-cpp_json_http-ip",
-  "hs-cpp_json_http-ip-ssl",
-  "hs-csharp_binary_buffered-ip",
-  "hs-csharp_binary_buffered-ip-ssl",
   "hs-csharp_binary_framed-ip",
-  "hs-csharp_binary_framed-ip-ssl",
-  "hs-csharp_compact_buffered-ip",
-  "hs-csharp_compact_buffered-ip-ssl",
   "hs-csharp_compact_framed-ip",
-  "hs-csharp_compact_framed-ip-ssl",
   "hs-csharp_json_buffered-ip",
-  "hs-csharp_json_buffered-ip-ssl",
   "hs-csharp_json_framed-ip",
-  "hs-csharp_json_framed-ip-ssl",
   "hs-go_binary_buffered-ip",
-  "hs-go_binary_buffered-ip-ssl",
   "hs-go_binary_framed-ip",
-  "hs-go_binary_framed-ip-ssl",
   "hs-go_compact_buffered-ip",
-  "hs-go_compact_buffered-ip-ssl",
   "hs-go_compact_framed-ip",
-  "hs-go_compact_framed-ip-ssl",
   "hs-go_json_buffered-ip",
-  "hs-go_json_buffered-ip-ssl",
   "hs-go_json_framed-ip",
-  "hs-go_json_framed-ip-ssl",
-  "hs-java_binary_buffered-ip-ssl",
-  "hs-java_binary_evhttp-http-ip",
-  "hs-java_binary_evhttp-http-ip-ssl",
-  "hs-java_binary_framed-fastframed-ip",
-  "hs-java_binary_framed-fastframed-ip-ssl",
-  "hs-java_binary_framed-ip",
-  "hs-java_binary_framed-ip-ssl",
-  "hs-java_binary_http-ip",
-  "hs-java_binary_http-ip-ssl",
-  "hs-java_compact_buffered-ip-ssl",
-  "hs-java_compact_evhttp-http-ip",
-  "hs-java_compact_evhttp-http-ip-ssl",
-  "hs-java_compact_framed-fastframed-ip",
-  "hs-java_compact_framed-fastframed-ip-ssl",
-  "hs-java_compact_framed-ip",
-  "hs-java_compact_framed-ip-ssl",
-  "hs-java_compact_http-ip",
-  "hs-java_compact_http-ip-ssl",
-  "hs-java_json_buffered-ip-ssl",
-  "hs-java_json_evhttp-http-ip",
-  "hs-java_json_evhttp-http-ip-ssl",
-  "hs-java_json_framed-fastframed-ip",
-  "hs-java_json_framed-fastframed-ip-ssl",
-  "hs-java_json_framed-ip",
-  "hs-java_json_framed-ip-ssl",
-  "hs-java_json_http-ip",
-  "hs-java_json_http-ip-ssl",
   "hs-nodejs_binary_buffered-ip",
-  "hs-nodejs_binary_buffered-ip-ssl",
   "hs-nodejs_binary_framed-ip",
-  "hs-nodejs_binary_framed-ip-ssl",
   "hs-nodejs_compact_buffered-ip",
-  "hs-nodejs_compact_buffered-ip-ssl",
   "hs-nodejs_compact_framed-ip",
-  "hs-nodejs_compact_framed-ip-ssl",
   "hs-nodejs_json_buffered-ip",
-  "hs-nodejs_json_buffered-ip-ssl",
   "hs-nodejs_json_framed-ip",
-  "hs-nodejs_json_framed-ip-ssl",
-  "hs-php_binary_framed-ip",
-  "hs-php_compact_framed-ip",
-  "hs-py_binary-accel_buffered-ip-ssl",
-  "hs-py_binary-accel_framed-ip",
-  "hs-py_binary-accel_framed-ip-ssl",
-  "hs-py_binary_buffered-ip-ssl",
-  "hs-py_binary_framed-ip",
-  "hs-py_binary_framed-ip-ssl",
-  "hs-py_compact_buffered-ip-ssl",
-  "hs-py_compact_framed-ip",
-  "hs-py_compact_framed-ip-ssl",
   "hs-py_json_buffered-ip",
-  "hs-py_json_buffered-ip-ssl",
   "hs-py_json_framed-ip",
-  "hs-py_json_framed-ip-ssl",
-  "hs-rb_binary-accel_framed-ip",
-  "hs-rb_binary_framed-ip",
-  "hs-rb_compact_framed-ip",
   "hs-rb_json_buffered-ip",
   "hs-rb_json_framed-ip",
   "java-csharp_binary_buffered-ip-ssl",
@@ -298,26 +186,28 @@
   "java-csharp_json_buffered-ip-ssl",
   "java-csharp_json_fastframed-framed-ip-ssl",
   "java-csharp_json_framed-ip-ssl",
-  "java-hs_binary_buffered-ip-ssl",
-  "java-hs_binary_fastframed-framed-ip",
-  "java-hs_binary_fastframed-framed-ip-ssl",
-  "java-hs_binary_framed-ip",
-  "java-hs_binary_framed-ip-ssl",
-  "java-hs_compact_buffered-ip-ssl",
-  "java-hs_compact_fastframed-framed-ip",
-  "java-hs_compact_fastframed-framed-ip-ssl",
-  "java-hs_compact_framed-ip",
-  "java-hs_compact_framed-ip-ssl",
-  "java-hs_json_buffered-ip-ssl",
+  "java-hs_json_buffered-ip",
   "java-hs_json_fastframed-framed-ip",
-  "java-hs_json_fastframed-framed-ip-ssl",
   "java-hs_json_framed-ip",
-  "java-hs_json_framed-ip-ssl",
   "java-nodejs_json_buffered-ip",
   "java-nodejs_json_buffered-ip-ssl",
   "java-rb_json_buffered-ip",
   "java-rb_json_fastframed-framed-ip",
   "java-rb_json_framed-ip",
+  "nodejs-c_glib_binary_buffered-ip",
+  "nodejs-c_glib_binary_framed-ip",
+  "nodejs-cpp_binary_buffered-ip",
+  "nodejs-cpp_binary_buffered-ip-ssl",
+  "nodejs-cpp_binary_framed-ip",
+  "nodejs-cpp_binary_framed-ip-ssl",
+  "nodejs-cpp_compact_buffered-ip",
+  "nodejs-cpp_compact_buffered-ip-ssl",
+  "nodejs-cpp_compact_framed-ip",
+  "nodejs-cpp_compact_framed-ip-ssl",
+  "nodejs-cpp_json_buffered-ip",
+  "nodejs-cpp_json_buffered-ip-ssl",
+  "nodejs-cpp_json_framed-ip",
+  "nodejs-cpp_json_framed-ip-ssl",
   "nodejs-csharp_binary_buffered-ip",
   "nodejs-csharp_binary_buffered-ip-ssl",
   "nodejs-csharp_binary_framed-ip",
@@ -330,17 +220,25 @@
   "nodejs-csharp_json_buffered-ip-ssl",
   "nodejs-csharp_json_framed-ip",
   "nodejs-csharp_json_framed-ip-ssl",
-  "nodejs-hs_binary_buffered-ip-ssl",
+  "nodejs-hs_binary_buffered-ip",
   "nodejs-hs_binary_framed-ip",
-  "nodejs-hs_binary_framed-ip-ssl",
-  "nodejs-hs_compact_buffered-ip-ssl",
+  "nodejs-hs_compact_buffered-ip",
   "nodejs-hs_compact_framed-ip",
-  "nodejs-hs_compact_framed-ip-ssl",
   "nodejs-hs_json_buffered-ip",
-  "nodejs-hs_json_buffered-ip-ssl",
   "nodejs-hs_json_framed-ip",
-  "nodejs-hs_json_framed-ip-ssl",
   "nodejs-java_json_buffered-ip-ssl",
+  "nodejs-py_binary-accel_buffered-ip",
+  "nodejs-py_binary-accel_buffered-ip-ssl",
+  "nodejs-py_binary-accel_framed-ip",
+  "nodejs-py_binary-accel_framed-ip-ssl",
+  "nodejs-py_binary_buffered-ip",
+  "nodejs-py_binary_buffered-ip-ssl",
+  "nodejs-py_binary_framed-ip",
+  "nodejs-py_binary_framed-ip-ssl",
+  "nodejs-py_compact_buffered-ip",
+  "nodejs-py_compact_buffered-ip-ssl",
+  "nodejs-py_compact_framed-ip",
+  "nodejs-py_compact_framed-ip-ssl",
   "nodejs-py_json_buffered-ip",
   "nodejs-py_json_buffered-ip-ssl",
   "nodejs-py_json_framed-ip",
@@ -354,116 +252,20 @@
   "nodejs-rb_json_buffered-ip",
   "nodejs-rb_json_framed-ip",
   "perl-php_binary_framed-ip",
-  "py-c_glib_accel-binary_buffered-ip",
-  "py-c_glib_accel-binary_framed-ip",
-  "py-c_glib_binary_buffered-ip",
-  "py-c_glib_binary_framed-ip",
-  "py-cpp_accel-binary_buffered-ip",
-  "py-cpp_accel-binary_buffered-ip-ssl",
-  "py-cpp_accel-binary_framed-ip",
-  "py-cpp_accel-binary_framed-ip-ssl",
-  "py-cpp_binary_buffered-ip",
-  "py-cpp_binary_buffered-ip-ssl",
-  "py-cpp_binary_framed-ip",
-  "py-cpp_binary_framed-ip-ssl",
-  "py-cpp_compact_buffered-ip",
-  "py-cpp_compact_buffered-ip-ssl",
-  "py-cpp_compact_framed-ip",
-  "py-cpp_compact_framed-ip-ssl",
-  "py-cpp_json_buffered-ip",
-  "py-cpp_json_buffered-ip-ssl",
-  "py-cpp_json_framed-ip",
-  "py-cpp_json_framed-ip-ssl",
-  "py-csharp_accel-binary_buffered-ip",
   "py-csharp_accel-binary_buffered-ip-ssl",
-  "py-csharp_accel-binary_framed-ip",
   "py-csharp_accel-binary_framed-ip-ssl",
-  "py-csharp_binary_buffered-ip",
   "py-csharp_binary_buffered-ip-ssl",
-  "py-csharp_binary_framed-ip",
   "py-csharp_binary_framed-ip-ssl",
-  "py-csharp_compact_buffered-ip",
   "py-csharp_compact_buffered-ip-ssl",
-  "py-csharp_compact_framed-ip",
   "py-csharp_compact_framed-ip-ssl",
-  "py-csharp_json_buffered-ip",
   "py-csharp_json_buffered-ip-ssl",
-  "py-csharp_json_framed-ip",
   "py-csharp_json_framed-ip-ssl",
-  "py-go_accel-binary_buffered-ip",
-  "py-go_accel-binary_buffered-ip-ssl",
-  "py-go_accel-binary_framed-ip",
-  "py-go_accel-binary_framed-ip-ssl",
-  "py-go_binary_buffered-ip",
-  "py-go_binary_buffered-ip-ssl",
-  "py-go_binary_framed-ip",
-  "py-go_binary_framed-ip-ssl",
-  "py-go_compact_buffered-ip",
-  "py-go_compact_buffered-ip-ssl",
-  "py-go_compact_framed-ip",
-  "py-go_compact_framed-ip-ssl",
-  "py-go_json_buffered-ip",
-  "py-go_json_buffered-ip-ssl",
-  "py-go_json_framed-ip",
-  "py-go_json_framed-ip-ssl",
-  "py-hs_accel-binary_buffered-ip",
-  "py-hs_accel-binary_buffered-ip-ssl",
-  "py-hs_accel-binary_framed-ip",
-  "py-hs_accel-binary_framed-ip-ssl",
-  "py-hs_binary_buffered-ip",
-  "py-hs_binary_buffered-ip-ssl",
-  "py-hs_binary_framed-ip",
-  "py-hs_binary_framed-ip-ssl",
-  "py-hs_compact_buffered-ip",
-  "py-hs_compact_buffered-ip-ssl",
-  "py-hs_compact_framed-ip",
-  "py-hs_compact_framed-ip-ssl",
   "py-hs_json_buffered-ip",
-  "py-hs_json_buffered-ip-ssl",
   "py-hs_json_framed-ip",
-  "py-hs_json_framed-ip-ssl",
-  "py-java_accel-binary_buffered-ip",
-  "py-java_accel-binary_buffered-ip-ssl",
-  "py-java_accel-binary_framed-fastframed-ip",
-  "py-java_accel-binary_framed-fastframed-ip-ssl",
-  "py-java_accel-binary_framed-ip",
-  "py-java_accel-binary_framed-ip-ssl",
-  "py-java_binary_buffered-ip",
-  "py-java_binary_buffered-ip-ssl",
-  "py-java_binary_framed-fastframed-ip",
-  "py-java_binary_framed-fastframed-ip-ssl",
-  "py-java_binary_framed-ip",
-  "py-java_binary_framed-ip-ssl",
-  "py-java_compact_buffered-ip",
-  "py-java_compact_buffered-ip-ssl",
-  "py-java_compact_framed-fastframed-ip",
-  "py-java_compact_framed-fastframed-ip-ssl",
-  "py-java_compact_framed-ip",
-  "py-java_compact_framed-ip-ssl",
-  "py-java_json_buffered-ip",
-  "py-java_json_buffered-ip-ssl",
-  "py-java_json_framed-fastframed-ip",
-  "py-java_json_framed-fastframed-ip-ssl",
-  "py-java_json_framed-ip",
-  "py-java_json_framed-ip-ssl",
-  "py-nodejs_accel-binary_buffered-ip",
-  "py-nodejs_accel-binary_buffered-ip-ssl",
-  "py-nodejs_accel-binary_framed-ip",
-  "py-nodejs_accel-binary_framed-ip-ssl",
-  "py-nodejs_binary_buffered-ip",
-  "py-nodejs_binary_buffered-ip-ssl",
-  "py-nodejs_binary_framed-ip",
-  "py-nodejs_binary_framed-ip-ssl",
-  "py-nodejs_compact_buffered-ip",
-  "py-nodejs_compact_buffered-ip-ssl",
-  "py-nodejs_compact_framed-ip",
-  "py-nodejs_compact_framed-ip-ssl",
   "py-nodejs_json_buffered-ip",
   "py-nodejs_json_buffered-ip-ssl",
   "py-nodejs_json_framed-ip",
   "py-nodejs_json_framed-ip-ssl",
-  "py-php_json_buffered-ip",
-  "py-php_json_framed-ip",
   "py-rb_accel-binary_buffered-ip",
   "py-rb_accel-binary_framed-ip",
   "py-rb_accel_buffered-ip",
@@ -480,11 +282,11 @@
   "rb-c_glib_accel-binary_framed-ip",
   "rb-c_glib_binary_buffered-ip",
   "rb-c_glib_binary_framed-ip",
+  "rb-cpp_json_buffered-ip",
+  "rb-cpp_json_framed-ip",
   "rb-csharp_json_buffered-ip",
   "rb-csharp_json_framed-ip",
-  "rb-hs_accel-binary_framed-ip",
-  "rb-hs_binary_framed-ip",
-  "rb-hs_compact_framed-ip",
+  "rb-hs_json_buffered-ip",
   "rb-hs_json_framed-ip",
   "rb-nodejs_json_buffered-ip",
   "rb-nodejs_json_framed-ip",
diff --git a/test/perl/TestClient.pl b/test/perl/TestClient.pl
index 40f8f59..9d4aab2 100755
--- a/test/perl/TestClient.pl
+++ b/test/perl/TestClient.pl
@@ -136,11 +136,11 @@
 # BOOL TEST
 #
 print("testBool(1)");
-my $u8 = $testClient->testBool(1);
-print(" = $u8\n");
+my $t = $testClient->testBool(1);
+print(" = $t\n");
 print("testBool(0)");
-my $u8 = $testClient->testBool(0);
-print(" = $u8\n");
+my $f = $testClient->testBool(0);
+print(" = $f\n");
 
 
 #
@@ -321,11 +321,17 @@
 my $insane = new ThriftTest::Insanity();
 $insane->{userMap}->{ThriftTest::Numberz::FIVE} = 5000;
 my $truck = new ThriftTest::Xtruct();
-$truck->string_thing("Truck");
-$truck->byte_thing(8);
-$truck->i32_thing(8);
-$truck->i64_thing(8);
+$truck->string_thing("Hello2");
+$truck->byte_thing(2);
+$truck->i32_thing(2);
+$truck->i64_thing(2);
+my $truck2 = new ThriftTest::Xtruct();
+$truck2->string_thing("Goodbye4");
+$truck2->byte_thing(4);
+$truck2->i32_thing(4);
+$truck2->i64_thing(4);
 push(@{$insane->{xtructs}}, $truck);
+push(@{$insane->{xtructs}}, $truck2);
 
 print("testInsanity()");
 my $whoa = $testClient->testInsanity($insane);
diff --git a/test/perl/TestServer.pl b/test/perl/TestServer.pl
index eebebc8..5bfa640 100644
--- a/test/perl/TestServer.pl
+++ b/test/perl/TestServer.pl
@@ -328,8 +328,8 @@
   my @goodbyes;
   push(@goodbyes, $goodbye);
   my $crazy = new ThriftTest::Insanity({userMap => { ThriftTest::Numberz::EIGHT => 8 }, xtructs => \@goodbyes});
-  my $loony = new ThriftTest::Insanity({userMap => { ThriftTest::Numberz::FIVE  => 5 }, xtructs => \@hellos});
-  my $result = { 1 => { ThriftTest::Numberz::TWO => $crazy, ThriftTest::Numberz::THREE => $crazy },
+  my $loony = new ThriftTest::Insanity();
+  my $result = { 1 => { ThriftTest::Numberz::TWO => $argument, ThriftTest::Numberz::THREE => $argument },
                  2 => { ThriftTest::Numberz::SIX => $loony } };
   return $result;
 }
diff --git a/test/py/TestClient.py b/test/py/TestClient.py
index 592a541..51111a6 100755
--- a/test/py/TestClient.py
+++ b/test/py/TestClient.py
@@ -19,11 +19,11 @@
 # under the License.
 #
 
-import sys, glob, os
-sys.path.insert(0, glob.glob(os.path.join(os.path.dirname(__file__),'../../lib/py/build/lib.*'))[0])
-
-import unittest
+import glob
+import os
+import sys
 import time
+import unittest
 from optparse import OptionParser
 
 parser = OptionParser()
@@ -53,8 +53,10 @@
 parser.set_defaults(framed=False, http_path=None, verbose=1, host='localhost', port=9090, proto='binary')
 options, args = parser.parse_args()
 
-script_dir = os.path.dirname(__file__)
+script_dir = os.path.abspath(os.path.dirname(__file__))
+lib_dir = os.path.join(os.path.dirname(os.path.dirname(script_dir)), 'lib', 'py', 'build', 'lib.*')
 sys.path.insert(0, os.path.join(script_dir, options.genpydir))
+sys.path.insert(0, glob.glob(lib_dir)[0])
 
 from ThriftTest import ThriftTest, SecondService
 from ThriftTest.ttypes import *
@@ -66,6 +68,7 @@
 from thrift.protocol import TCompactProtocol
 from thrift.protocol import TJSONProtocol
 
+
 class AbstractTest(unittest.TestCase):
   def setUp(self):
     if options.http_path:
@@ -95,36 +98,49 @@
     self.transport.close()
 
   def testVoid(self):
+    print('testVoid')
     self.client.testVoid()
 
   def testString(self):
+    print('testString')
     self.assertEqual(self.client.testString('Python' * 20), 'Python' * 20)
     self.assertEqual(self.client.testString(''), '')
 
   def testBool(self):
+    print('testBool')
     self.assertEqual(self.client.testBool(True), True)
     self.assertEqual(self.client.testBool(False), False)
 
   def testByte(self):
+    print('testByte')
     self.assertEqual(self.client.testByte(63), 63)
     self.assertEqual(self.client.testByte(-127), -127)
 
   def testI32(self):
+    print('testI32')
     self.assertEqual(self.client.testI32(-1), -1)
     self.assertEqual(self.client.testI32(0), 0)
 
   def testI64(self):
+    print('testI64')
     self.assertEqual(self.client.testI64(1), 1)
     self.assertEqual(self.client.testI64(-34359738368), -34359738368)
 
   def testDouble(self):
+    print('testDouble')
     self.assertEqual(self.client.testDouble(-5.235098235), -5.235098235)
     self.assertEqual(self.client.testDouble(0), 0)
     self.assertEqual(self.client.testDouble(-1), -1)
 
-  # TODO: def testBinary(self)	...
-	
+  def testBinary(self):
+    if isinstance(self, JSONTest):
+      self.skipTest('JSON protocol does not handle binary correctly.')
+    print('testBinary')
+    val = bytearray([i for i in range(0, 256)])
+    self.assertEqual(bytearray(self.client.testBinary(bytes(val))), val)
+
   def testStruct(self):
+    print('testStruct')
     x = Xtruct()
     x.string_thing = "Zero"
     x.byte_thing = 1
@@ -134,23 +150,26 @@
     self.assertEqual(y, x)
 
   def testNest(self):
-    inner = Xtruct(string_thing="Zero", byte_thing=1, i32_thing=-3,
-      i64_thing=-5)
+    print('testNest')
+    inner = Xtruct(string_thing="Zero", byte_thing=1, i32_thing=-3, i64_thing=-5)
     x = Xtruct2(struct_thing=inner, byte_thing=0, i32_thing=0)
     y = self.client.testNest(x)
     self.assertEqual(y, x)
 
   def testMap(self):
+    print('testMap')
     x = {0:1, 1:2, 2:3, 3:4, -1:-2}
     y = self.client.testMap(x)
     self.assertEqual(y, x)
 
   def testSet(self):
+    print('testSet')
     x = set([8, 1, 42])
     y = self.client.testSet(x)
     self.assertEqual(y, x)
 
   def testList(self):
+    print('testList')
     x = [1, 4, 9, -42]
     y = self.client.testList(x)
     self.assertEqual(y, x)
diff --git a/test/py/TestServer.py b/test/py/TestServer.py
index 89b74da..b5696ca 100755
--- a/test/py/TestServer.py
+++ b/test/py/TestServer.py
@@ -19,10 +19,16 @@
 # under the License.
 #
 from __future__ import division
-import sys, glob, time, os
-sys.path.insert(0, glob.glob(os.path.join(os.path.dirname(__file__),'../../lib/py/build/lib.*'))[0])
+import glob
+import logging
+import os
+import sys
+import time
 from optparse import OptionParser
 
+# Print TServer log to stdout so that the test-runner can redirect it to log files
+logging.basicConfig()
+
 parser = OptionParser()
 parser.add_option('--genpydir', type='string', dest='genpydir',
                   default='gen-py',
@@ -46,8 +52,11 @@
 parser.set_defaults(port=9090, verbose=1, proto='binary')
 options, args = parser.parse_args()
 
-script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in
+script_dir = os.path.realpath(os.path.dirname(__file__))  # <-- absolute dir the script is in
+lib_dir = os.path.join(os.path.dirname(os.path.dirname(script_dir)), 'lib', 'py', 'build', 'lib.*')
+
 sys.path.insert(0, os.path.join(script_dir, options.genpydir))
+sys.path.insert(0, glob.glob(lib_dir)[0])
 
 from ThriftTest import ThriftTest
 from ThriftTest.ttypes import *
@@ -60,65 +69,67 @@
 from thrift.protocol import TJSONProtocol
 from thrift.server import TServer, TNonblockingServer, THttpServer
 
-PROT_FACTORIES = {'binary': TBinaryProtocol.TBinaryProtocolFactory,
+PROT_FACTORIES = {
+    'binary': TBinaryProtocol.TBinaryProtocolFactory,
     'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory,
     'compact': TCompactProtocol.TCompactProtocolFactory,
-    'json': TJSONProtocol.TJSONProtocolFactory}
+    'json': TJSONProtocol.TJSONProtocolFactory,
+}
 
-class TestHandler:
 
+class TestHandler(object):
   def testVoid(self):
     if options.verbose > 1:
-      print 'testVoid()'
+      print('testVoid()')
 
   def testString(self, str):
     if options.verbose > 1:
-      print 'testString(%s)' % str
+      print('testString(%s)' % str)
     return str
 
   def testBool(self, boolean):
     if options.verbose > 1:
-      print 'testBool(%s)' % str(boolean).lower()
+      print('testBool(%s)' % str(boolean).lower())
     return boolean
 
   def testByte(self, byte):
     if options.verbose > 1:
-      print 'testByte(%d)' % byte
+      print('testByte(%d)' % byte)
     return byte
 
   def testI16(self, i16):
     if options.verbose > 1:
-      print 'testI16(%d)' % i16
+      print('testI16(%d)' % i16)
     return i16
 
   def testI32(self, i32):
     if options.verbose > 1:
-      print 'testI32(%d)' % i32
+      print('testI32(%d)' % i32)
     return i32
 
   def testI64(self, i64):
     if options.verbose > 1:
-      print 'testI64(%d)' % i64
+      print('testI64(%d)' % i64)
     return i64
 
   def testDouble(self, dub):
     if options.verbose > 1:
-      print 'testDouble(%f)' % dub
+      print('testDouble(%f)' % dub)
     return dub
 
   def testBinary(self, thing):
     if options.verbose > 1:
-      print 'testBinary()' # TODO: hex output
-    return thring
-	
+      print('testBinary()')  # TODO: hex output
+    return thing
+
   def testStruct(self, thing):
     if options.verbose > 1:
-      print 'testStruct({%s, %d, %d, %d})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing)
+      print('testStruct({%s, %d, %d, %d})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing))
     return thing
 
   def testException(self, arg):
-    #if options.verbose > 1:
-    print 'testException(%s)' % arg
+    # if options.verbose > 1:
+    print('testException(%s)' % arg)
     if arg == 'Xception':
       raise Xception(errorCode=1001, message=arg)
     elif arg == 'TException':
@@ -126,7 +137,7 @@
 
   def testMultiException(self, arg0, arg1):
     if options.verbose > 1:
-      print 'testMultiException(%s, %s)' % (arg0, arg1)
+      print('testMultiException(%s, %s)' % (arg0, arg1))
     if arg0 == 'Xception':
       raise Xception(errorCode=1001, message='This is an Xception')
     elif arg0 == 'Xception2':
@@ -137,54 +148,78 @@
 
   def testOneway(self, seconds):
     if options.verbose > 1:
-      print 'testOneway(%d) => sleeping...' % seconds
-    time.sleep(seconds / 3) # be quick
+      print('testOneway(%d) => sleeping...' % seconds)
+    time.sleep(seconds / 3)  # be quick
     if options.verbose > 1:
-      print 'done sleeping'
+      print('done sleeping')
 
   def testNest(self, thing):
     if options.verbose > 1:
-      print 'testNest(%s)' % thing
+      print('testNest(%s)' % thing)
     return thing
 
   def testMap(self, thing):
     if options.verbose > 1:
-      print 'testMap(%s)' % thing
+      print('testMap(%s)' % thing)
+    return thing
+
+  def testStringMap(self, thing):
+    if options.verbose > 1:
+      print('testStringMap(%s)' % thing)
     return thing
 
   def testSet(self, thing):
     if options.verbose > 1:
-      print 'testSet(%s)' % thing
+      print('testSet(%s)' % thing)
     return thing
 
   def testList(self, thing):
     if options.verbose > 1:
-      print 'testList(%s)' % thing
+      print('testList(%s)' % thing)
     return thing
 
   def testEnum(self, thing):
     if options.verbose > 1:
-      print 'testEnum(%s)' % thing
+      print('testEnum(%s)' % thing)
     return thing
 
   def testTypedef(self, thing):
     if options.verbose > 1:
-      print 'testTypedef(%s)' % thing
+      print('testTypedef(%s)' % thing)
     return thing
 
   def testMapMap(self, thing):
     if options.verbose > 1:
-      print 'testMapMap(%s)' % thing
-    return {thing: {thing: thing}}
+      print('testMapMap(%s)' % thing)
+    return {
+      -4: {
+        -4: -4,
+        -3: -3,
+        -2: -2,
+        -1: -1,
+      },
+      4: {
+        4: 4,
+        3: 3,
+        2: 2,
+        1: 1,
+      },
+    }
 
   def testInsanity(self, argument):
     if options.verbose > 1:
-      print 'testInsanity(%s)' % argument
-    return {123489: {Numberz.ONE:argument}}
+      print('testInsanity(%s)' % argument)
+    return {
+      1: {
+        2: argument,
+        3: argument,
+      },
+      2: {6: Insanity()},
+    }
 
   def testMulti(self, arg0, arg1, arg2, arg3, arg4, arg5):
     if options.verbose > 1:
-      print 'testMulti(%s)' % [arg0, arg1, arg2, arg3, arg4, arg5]
+      print('testMulti(%s)' % [arg0, arg1, arg2, arg3, arg4, arg5])
     return Xtruct(string_thing='Hello2',
                   byte_thing=arg0, i32_thing=arg1, i64_thing=arg2)
 
@@ -212,8 +247,7 @@
 
 # set up server transport and transport factory
 
-rel_path = "../keys/server.pem"
-abs_key_path = os.path.join(script_dir, rel_path)
+abs_key_path = os.path.join(os.path.dirname(script_dir), 'keys', 'server.pem')
 
 host = None
 if options.ssl:
@@ -243,14 +277,15 @@
   from thrift.server import TProcessPoolServer
   server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
   server.setNumWorkers(5)
+
   def set_alarm():
     def clean_shutdown(signum, frame):
       for worker in server.workers:
         if options.verbose > 0:
-          print 'Terminating worker: %s' % worker
+          print('Terminating worker: %s' % worker)
         worker.terminate()
       if options.verbose > 0:
-        print 'Requesting server to stop()'
+        print('Requesting server to stop()')
       try:
         server.stop()
       except:
diff --git a/test/rebuild_known_failures.sh b/test/rebuild_known_failures.sh
new file mode 100644
index 0000000..08869fe
--- /dev/null
+++ b/test/rebuild_known_failures.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+if [ -z $1 ]; then
+  echo Usage: $0 LANGUAGE
+  echo Re-list all failures of a specific LANGUAGE into known_failures_Linux.json
+  echo LANGUAGE should be library name like cpp, java, py etc
+  exit 1
+fi
+
+if [ -z $PYTHON]; then
+  PYTHON=python
+fi
+
+TARGET_LANG=$1
+OUT_FILE=known_failures_Linux.json
+echo Rebuilding known failures for $TARGET_LANG
+
+TMPFILE=.__tmp__rebuild__
+grep -v -e "\"$1-" -e "\-$1_" $OUT_FILE > $TMPFILE
+mv $TMPFILE $OUT_FILE
+$PYTHON test.py --client $1
+$PYTHON test.py -U merge
+$PYTHON test.py --server $1
+$PYTHON test.py -U merge
diff --git a/test/tests.json b/test/tests.json
index d7caccb..cb2f0e2 100644
--- a/test/tests.json
+++ b/test/tests.json
@@ -145,19 +145,19 @@
     },
     "client": {
       "timeout": 6,
+      "transports": [
+        "http"
+      ],
       "command": [
         "TestClient"
       ]
     },
     "transports": [
       "buffered",
-      "framed",
-      "http",
-      "http:evhttp"
+      "framed"
     ],
     "sockets": [
-      "ip",
-      "ip-ssl"
+      "ip"
     ],
     "protocols": [
       "compact",
@@ -173,6 +173,7 @@
       "extra_args": ["TSimpleServer"],
       "command": [
         "TestServer.py",
+        "--verbose",
         "--genpydir=gen-py"
       ]
     },