You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by ns...@apache.org on 2016/01/23 16:21:52 UTC

[1/4] thrift git commit: THRIFT-3568 THeader server crashes on readSlow Client: C++ Patch: Nobuaki Sukegawa

Repository: thrift
Updated Branches:
  refs/heads/master 607697054 -> 9890c28b7


THRIFT-3568 THeader server crashes on readSlow
Client: C++
Patch: Nobuaki Sukegawa

This closes #807


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/9890c28b
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/9890c28b
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/9890c28b

Branch: refs/heads/master
Commit: 9890c28b7e0f99e0ef1be4a44e8f111d5085336c
Parents: bd16530
Author: Nobuaki Sukegawa <ns...@apache.org>
Authored: Tue Jan 19 04:12:45 2016 +0900
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Jan 24 00:13:44 2016 +0900

----------------------------------------------------------------------
 .../src/thrift/transport/TBufferTransports.h    |  4 +--
 .../src/thrift/transport/THeaderTransport.cpp   | 12 ++------
 lib/cpp/src/thrift/transport/THeaderTransport.h | 31 +++++---------------
 test/features/known_failures_Linux.json         |  2 --
 test/known_failures_Linux.json                  | 18 ++++--------
 5 files changed, 18 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/9890c28b/lib/cpp/src/thrift/transport/TBufferTransports.h
----------------------------------------------------------------------
diff --git a/lib/cpp/src/thrift/transport/TBufferTransports.h b/lib/cpp/src/thrift/transport/TBufferTransports.h
index 013c6e0..e690d0c 100644
--- a/lib/cpp/src/thrift/transport/TBufferTransports.h
+++ b/lib/cpp/src/thrift/transport/TBufferTransports.h
@@ -372,7 +372,7 @@ public:
    * TVirtualTransport provides a default implementation of readAll().
    * We want to use the TBufferBase version instead.
    */
-  uint32_t readAll(uint8_t* buf, uint32_t len) { return TBufferBase::readAll(buf, len); }
+  using TBufferBase::readAll;
 
   /**
    * Returns the origin of the underlying transport
@@ -396,7 +396,7 @@ protected:
    * Returns true if a frame was read successfully, or false on EOF.
    * (Raises a TTransportException if EOF occurs after a partial frame.)
    */
-  bool readFrame();
+  virtual bool readFrame();
 
   void initPointers() {
     setReadBuffer(NULL, 0);

http://git-wip-us.apache.org/repos/asf/thrift/blob/9890c28b/lib/cpp/src/thrift/transport/THeaderTransport.cpp
----------------------------------------------------------------------
diff --git a/lib/cpp/src/thrift/transport/THeaderTransport.cpp b/lib/cpp/src/thrift/transport/THeaderTransport.cpp
index 79bc5ea..fd24fed 100644
--- a/lib/cpp/src/thrift/transport/THeaderTransport.cpp
+++ b/lib/cpp/src/thrift/transport/THeaderTransport.cpp
@@ -40,14 +40,7 @@ namespace transport {
 using namespace apache::thrift::protocol;
 using apache::thrift::protocol::TBinaryProtocol;
 
-uint32_t THeaderTransport::readAll(uint8_t* buf, uint32_t len) {
-  // We want to call TBufferBase's version here, because
-  // TFramedTransport would try and call its own readFrame function
-  return TBufferBase::readAll(buf, len);
-}
-
 uint32_t THeaderTransport::readSlow(uint8_t* buf, uint32_t len) {
-
   if (clientType == THRIFT_UNFRAMED_DEPRECATED) {
     return transport_->read(buf, len);
   }
@@ -70,7 +63,7 @@ void THeaderTransport::ensureReadBuffer(uint32_t sz) {
   }
 }
 
-bool THeaderTransport::readFrame(uint32_t minFrameSize) {
+bool THeaderTransport::readFrame() {
   // szN is network byte order of sz
   uint32_t szN;
   uint32_t sz;
@@ -99,6 +92,7 @@ bool THeaderTransport::readFrame(uint32_t minFrameSize) {
 
   sz = ntohl(szN);
 
+  uint32_t minFrameSize = 0;
   ensureReadBuffer(minFrameSize + 4);
 
   if ((sz & TBinaryProtocol::VERSION_MASK) == (uint32_t)TBinaryProtocol::VERSION_1) {
@@ -368,7 +362,7 @@ void THeaderTransport::resetProtocol() {
   clientType = THRIFT_HEADER_CLIENT_TYPE;
 
   // Read the header and decide which protocol to go with
-  readFrame(0);
+  readFrame();
 }
 
 uint32_t THeaderTransport::getWriteBytes() {

http://git-wip-us.apache.org/repos/asf/thrift/blob/9890c28b/lib/cpp/src/thrift/transport/THeaderTransport.h
----------------------------------------------------------------------
diff --git a/lib/cpp/src/thrift/transport/THeaderTransport.h b/lib/cpp/src/thrift/transport/THeaderTransport.h
index 94135ea..a125632 100644
--- a/lib/cpp/src/thrift/transport/THeaderTransport.h
+++ b/lib/cpp/src/thrift/transport/THeaderTransport.h
@@ -22,6 +22,7 @@
 
 #include <bitset>
 #include <vector>
+#include <stdexcept>
 #include <string>
 #include <map>
 
@@ -69,7 +70,7 @@ public:
 
   /// Use default buffer sizes.
   explicit THeaderTransport(const boost::shared_ptr<TTransport>& transport)
-    : transport_(transport),
+    : TVirtualTransport(transport),
       outTransport_(transport),
       protoId(T_COMPACT_PROTOCOL),
       clientType(THRIFT_HEADER_CLIENT_TYPE),
@@ -77,12 +78,13 @@ public:
       flags(0),
       tBufSize_(0),
       tBuf_(NULL) {
+    if (!transport_) throw std::invalid_argument("transport is empty");
     initBuffers();
   }
 
   THeaderTransport(const boost::shared_ptr<TTransport> inTransport,
                    const boost::shared_ptr<TTransport> outTransport)
-    : transport_(inTransport),
+    : TVirtualTransport(inTransport),
       outTransport_(outTransport),
       protoId(T_COMPACT_PROTOCOL),
       clientType(THRIFT_HEADER_CLIENT_TYPE),
@@ -90,34 +92,16 @@ public:
       flags(0),
       tBufSize_(0),
       tBuf_(NULL) {
+    if (!transport_) throw std::invalid_argument("inTransport is empty");
+    if (!outTransport_) throw std::invalid_argument("outTransport is empty");
     initBuffers();
   }
 
-  void open() { transport_->open(); }
-
-  bool isOpen() { return transport_->isOpen(); }
-
-  bool peek() { return (this->rBase_ < this->rBound_) || transport_->peek(); }
-
-  void close() {
-    flush();
-    transport_->close();
-  }
-
   virtual uint32_t readSlow(uint8_t* buf, uint32_t len);
-  virtual uint32_t readAll(uint8_t* buf, uint32_t len);
   virtual void flush();
 
   void resizeTransformBuffer(uint32_t additionalSize = 0);
 
-  boost::shared_ptr<TTransport> getUnderlyingTransport() { return transport_; }
-
-  /*
-   * TVirtualTransport provides a default implementation of readAll().
-   * We want to use the TBufferBase version instead.
-   */
-  using TBufferBase::readAll;
-
   uint16_t getProtocolId() const;
   void setProtocolId(uint16_t protoId) { this->protoId = protoId; }
 
@@ -191,7 +175,7 @@ protected:
    * Returns true if a frame was read successfully, or false on EOF.
    * (Raises a TTransportException if EOF occurs after a partial frame.)
    */
-  bool readFrame(uint32_t minFrameSize);
+  virtual bool readFrame();
 
   void ensureReadBuffer(uint32_t sz);
   uint32_t getWriteBytes();
@@ -201,7 +185,6 @@ protected:
     setWriteBuffer(wBuf_.get(), wBufSize_);
   }
 
-  boost::shared_ptr<TTransport> transport_;
   boost::shared_ptr<TTransport> outTransport_;
 
   // 0 and 16th bits must be 0 to differentiate from framed & unframed

http://git-wip-us.apache.org/repos/asf/thrift/blob/9890c28b/test/features/known_failures_Linux.json
----------------------------------------------------------------------
diff --git a/test/features/known_failures_Linux.json b/test/features/known_failures_Linux.json
index fd96250..9bf600d 100644
--- a/test/features/known_failures_Linux.json
+++ b/test/features/known_failures_Linux.json
@@ -1,8 +1,6 @@
 [
   "c_glib-limit_container_length_binary_buffered-ip",
   "c_glib-limit_string_length_binary_buffered-ip",
-  "cpp-theader_framed_binary_header_buffered-ip",
-  "cpp-theader_unframed_binary_header_buffered-ip",
   "csharp-limit_container_length_binary_buffered-ip",
   "csharp-limit_container_length_compact_buffered-ip",
   "csharp-limit_string_length_binary_buffered-ip",

http://git-wip-us.apache.org/repos/asf/thrift/blob/9890c28b/test/known_failures_Linux.json
----------------------------------------------------------------------
diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json
index 25eea2d..ac409bf 100644
--- a/test/known_failures_Linux.json
+++ b/test/known_failures_Linux.json
@@ -9,14 +9,8 @@
   "cpp-cpp_compact_http-domain",
   "cpp-cpp_compact_http-ip",
   "cpp-cpp_compact_http-ip-ssl",
-  "cpp-cpp_header_buffered-domain",
-  "cpp-cpp_header_buffered-ip",
   "cpp-cpp_header_buffered-ip-ssl",
-  "cpp-cpp_header_framed-domain",
-  "cpp-cpp_header_framed-ip",
   "cpp-cpp_header_framed-ip-ssl",
-  "cpp-cpp_header_http-domain",
-  "cpp-cpp_header_http-ip",
   "cpp-cpp_header_http-ip-ssl",
   "cpp-cpp_json_buffered-ip-ssl",
   "cpp-cpp_json_framed-ip",
@@ -60,6 +54,12 @@
   "csharp-nodejs_json_framed-ip-ssl",
   "csharp-perl_binary_buffered-ip-ssl",
   "csharp-perl_binary_framed-ip-ssl",
+  "csharp-py3_binary_buffered-ip-ssl",
+  "csharp-py3_binary_framed-ip-ssl",
+  "csharp-py3_compact_buffered-ip-ssl",
+  "csharp-py3_compact_framed-ip-ssl",
+  "csharp-py3_json_buffered-ip-ssl",
+  "csharp-py3_json_framed-ip-ssl",
   "csharp-py_binary-accel_buffered-ip-ssl",
   "csharp-py_binary-accel_framed-ip-ssl",
   "csharp-py_binary_buffered-ip-ssl",
@@ -68,12 +68,6 @@
   "csharp-py_compact_framed-ip-ssl",
   "csharp-py_json_buffered-ip-ssl",
   "csharp-py_json_framed-ip-ssl",
-  "csharp-py3_binary_buffered-ip-ssl",
-  "csharp-py3_binary_framed-ip-ssl",
-  "csharp-py3_compact_buffered-ip-ssl",
-  "csharp-py3_compact_framed-ip-ssl",
-  "csharp-py3_json_buffered-ip-ssl",
-  "csharp-py3_json_framed-ip-ssl",
   "erl-cpp_compact_buffered-ip",
   "erl-cpp_compact_buffered-ip-ssl",
   "erl-cpp_compact_framed-ip",


[4/4] thrift git commit: THRIFT-3555 'configure' script does not honor --with-openssl= for libcrypto for BN_init Client: Build Patch: Nobuaki Sukegawa

Posted by ns...@apache.org.
THRIFT-3555 'configure' script does not honor --with-openssl=<path> for libcrypto for BN_init
Client: Build
Patch: Nobuaki Sukegawa

This closes #805


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/a837085e
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/a837085e
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/a837085e

Branch: refs/heads/master
Commit: a837085ecea66e4dcbd96ef906fea3a5273b91ca
Parents: 6076970
Author: Nobuaki Sukegawa <ns...@apache.org>
Authored: Tue Jan 19 00:48:46 2016 +0900
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Jan 24 00:13:44 2016 +0900

----------------------------------------------------------------------
 configure.ac             | 15 ---------------
 lib/cpp/Makefile.am      |  4 ++--
 lib/cpp/test/Makefile.am |  4 +++-
 3 files changed, 5 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/a837085e/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 92dc58c..cca432c 100755
--- a/configure.ac
+++ b/configure.ac
@@ -571,21 +571,6 @@ dnl and we haven't yet found a system where this is a problem.
 AC_CHECK_LIB(rt, clock_gettime)
 AC_CHECK_LIB(socket, setsockopt)
 
-if test "$have_cpp" = "yes" ; then
-# mingw toolchain used to build "Thrift Compiler for Windows"
-# does not support libcrypto, so we just check if we building the cpp library
-AC_CHECK_LIB(crypto,
-    BN_init,
-    [AC_CHECK_LIB(ssl,
-        SSL_ctrl,
-        [LIBS="-lssl -lcrypto $LIBS"],
-        [AC_MSG_ERROR(["Error: libssl required"])],
-        -lcrypto
-    )],
-    [AC_MSG_ERROR(["Error: libcrypto required."])]
-)
-fi
-
 AC_TYPE_INT16_T
 AC_TYPE_INT32_T
 AC_TYPE_INT64_T

http://git-wip-us.apache.org/repos/asf/thrift/blob/a837085e/lib/cpp/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
index dac840a..6fd15d2 100755
--- a/lib/cpp/Makefile.am
+++ b/lib/cpp/Makefile.am
@@ -35,7 +35,8 @@ pkgconfigdir = $(libdir)/pkgconfig
 
 lib_LTLIBRARIES = libthrift.la
 pkgconfig_DATA = thrift.pc
-libthrift_la_LDFLAGS = -release $(VERSION) $(BOOST_LDFLAGS) $(OPENSSL_LDFLAGS)
+libthrift_la_LDFLAGS = -release $(VERSION)
+libthrift_la_LIBADD = $(BOOST_LDFLAGS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS)
 
 ## We only build the extra libraries if we have the dependencies,
 ## but we install all of the headers unconditionally.
@@ -58,7 +59,6 @@ endif
 
 AM_CXXFLAGS = -Wall -Wextra -pedantic
 AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(OPENSSL_INCLUDES) -I$(srcdir)/src -D__STDC_LIMIT_MACROS
-AM_LDFLAGS = $(BOOST_LDFLAGS) $(OPENSSL_LDFLAGS)
 
 # Define the source files for the module
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/a837085e/lib/cpp/test/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/cpp/test/Makefile.am b/lib/cpp/test/Makefile.am
index 1895afc..5f3b117 100755
--- a/lib/cpp/test/Makefile.am
+++ b/lib/cpp/test/Makefile.am
@@ -326,7 +326,9 @@ OpenSSLManualInitTest_SOURCES = \
 
 OpenSSLManualInitTest_LDADD = \
 	$(top_builddir)/lib/cpp/libthrift.la \
-	$(BOOST_TEST_LDADD)
+	$(BOOST_TEST_LDADD) \
+	$(OPENSSL_LDFLAGS) \
+	$(OPENSSL_LIBS)
 
 #
 # Common thrift code generation rules


[2/4] thrift git commit: THRIFT-3576 Boost test --log_format arg does not accept lowercase Client: Test (C++) Patch: Nobuaki Sukegawa

Posted by ns...@apache.org.
THRIFT-3576 Boost test --log_format arg does not accept lowercase
Client: Test (C++)
Patch: Nobuaki Sukegawa

This closes #814


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/3d600bfe
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/3d600bfe
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/3d600bfe

Branch: refs/heads/master
Commit: 3d600bfec3938bcee0008592e25cb1489bc782fa
Parents: a837085
Author: Nobuaki Sukegawa <ns...@apache.org>
Authored: Sat Jan 23 22:45:20 2016 +0900
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Jan 24 00:13:44 2016 +0900

----------------------------------------------------------------------
 lib/cpp/test/Makefile.am | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/3d600bfe/lib/cpp/test/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/cpp/test/Makefile.am b/lib/cpp/test/Makefile.am
index 5f3b117..162dc19 100755
--- a/lib/cpp/test/Makefile.am
+++ b/lib/cpp/test/Makefile.am
@@ -101,7 +101,7 @@ endif
 TESTS_ENVIRONMENT= \
 	BOOST_TEST_LOG_SINK=tests.xml \
 	BOOST_TEST_LOG_LEVEL=test_suite \
-	BOOST_TEST_LOG_FORMAT=xml
+	BOOST_TEST_LOG_FORMAT=XML
 
 TESTS = \
 	$(check_PROGRAMS)


[3/4] thrift git commit: THRIFT-3571 Make feature test result browsable Client: Test Patch: Nobuaki Sukegawa

Posted by ns...@apache.org.
THRIFT-3571 Make feature test result browsable
Client: Test
Patch: Nobuaki Sukegawa

This closes #809


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/bd165305
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/bd165305
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/bd165305

Branch: refs/heads/master
Commit: bd165305fa398afb47ac46b924414f6c9afb9b1f
Parents: 3d600bf
Author: Nobuaki Sukegawa <ns...@apache.org>
Authored: Tue Jan 19 11:10:07 2016 +0900
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Jan 24 00:13:44 2016 +0900

----------------------------------------------------------------------
 .gitignore                 |  1 +
 Makefile.am                |  6 +++
 configure.ac               |  1 +
 test/Makefile.am           |  5 ++-
 test/crossrunner/report.py | 23 +++++++----
 test/crossrunner/run.py    |  6 +--
 test/features/Makefile.am  | 27 ++++++++++++
 test/features/index.html   | 51 +++++++++++++++++++++++
 test/index.html            | 51 +++++++++++++++++++++++
 test/result.html           | 91 -----------------------------------------
 test/result.js             | 64 +++++++++++++++++++++++++++++
 test/test.py               | 43 ++++---------------
 12 files changed, 229 insertions(+), 140 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 632bd80..5dad747 100644
--- a/.gitignore
+++ b/.gitignore
@@ -240,6 +240,7 @@ erl_crash.dump
 /missing
 /node_modules/
 /stamp-h1
+/test/features/results.json
 /test/results.json
 /test/c_glib/test_client
 /test/c_glib/test_server

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/Makefile.am
----------------------------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
index f2ce16a..8ed400d 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,9 +55,15 @@ else
 CROSS_PY=$(PYTHON)
 endif
 
+if WITH_PYTHON
 cross: precross
 	$(CROSS_PY) test/test.py -F.* -s --server $(CROSS_LANGS_COMMA_SEPARATED)
 	$(CROSS_PY) test/test.py -s --server $(CROSS_LANGS_COMMA_SEPARATED) --client $(CROSS_LANGS_COMMA_SEPARATED)
+else
+# feature test needs python build
+cross: precross
+	$(CROSS_PY) test/test.py -s --server $(CROSS_LANGS_COMMA_SEPARATED) --client $(CROSS_LANGS_COMMA_SEPARATED)
+endif
 
 TIMES = 1 2 3
 fail: precross

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index cca432c..615c301 100755
--- a/configure.ac
+++ b/configure.ac
@@ -740,6 +740,7 @@ AC_CONFIG_FILES([
   lib/xml/Makefile
   lib/xml/test/Makefile
   test/Makefile
+  test/features/Makefile
   test/c_glib/Makefile
   test/cpp/Makefile
   test/erl/Makefile

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/test/Makefile.am
----------------------------------------------------------------------
diff --git a/test/Makefile.am b/test/Makefile.am
index c1fd589..6db171f 100755
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -17,7 +17,7 @@
 # under the License.
 #
 
-SUBDIRS =
+SUBDIRS = features
 PRECROSS_TARGET =
 
 if WITH_C_GLIB
@@ -124,7 +124,8 @@ EXTRA_DIST = \
 	tests.json \
 	ThriftTest.thrift \
 	TypedefTest.thrift \
-	result.html \
+	result.js \
+	index.html \
 	README.md \
 	valgrind.suppress
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/test/crossrunner/report.py
----------------------------------------------------------------------
diff --git a/test/crossrunner/report.py b/test/crossrunner/report.py
index ad98969..a84e891 100644
--- a/test/crossrunner/report.py
+++ b/test/crossrunner/report.py
@@ -33,7 +33,7 @@ from .compat import logfile_open, path_join, str_join
 from .test import TestEntry
 
 LOG_DIR = 'log'
-RESULT_HTML = 'result.html'
+RESULT_HTML = 'index.html'
 RESULT_JSON = 'results.json'
 FAIL_JSON = 'known_failures_%s.json'
 
@@ -209,11 +209,12 @@ class ExecReporter(TestReporter):
 
 
 class SummaryReporter(TestReporter):
-  def __init__(self, testdir, concurrent=True):
+  def __init__(self, basedir, testdir_relative, concurrent=True):
     super(SummaryReporter, self).__init__()
-    self.testdir = testdir
-    self.logdir = path_join(testdir, LOG_DIR)
-    self.out_path = path_join(testdir, RESULT_JSON)
+    self._basedir = basedir
+    self._testdir_rel = testdir_relative
+    self.logdir = path_join(self.testdir, LOG_DIR)
+    self.out_path = path_join(self.testdir, RESULT_JSON)
     self.concurrent = concurrent
     self.out = sys.stdout
     self._platform = platform.system()
@@ -221,12 +222,16 @@ class SummaryReporter(TestReporter):
     self._tests = []
     if not os.path.exists(self.logdir):
       os.mkdir(self.logdir)
-    self._known_failures = load_known_failures(testdir)
+    self._known_failures = load_known_failures(self.testdir)
     self._unexpected_success = []
     self._unexpected_failure = []
     self._expected_failure = []
     self._print_header()
 
+  @property
+  def testdir(self):
+    return path_join(self._basedir, self._testdir_rel)
+
   def _get_revision(self):
     p = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'],
                          cwd=self.testdir, stdout=subprocess.PIPE)
@@ -296,11 +301,11 @@ class SummaryReporter(TestReporter):
     self._assemble_log('known failures', self._expected_failure)
     self.out.writelines([
       'You can browse results at:\n',
-      '\tfile://%s/%s\n' % (self.testdir, RESULT_HTML),
+      '\tfile://%s/%s\n' % (self._basedir, RESULT_HTML),
       '# If you use Chrome, run:\n',
-      '# \tcd %s\n#\t%s\n' % (self.testdir, self._http_server_command(8001)),
+      '# \tcd %s\n#\t%s\n' % (self._basedir, self._http_server_command(8001)),
       '# then browse:\n',
-      '# \thttp://localhost:%d/test/%s\n' % (8001, RESULT_HTML),
+      '# \thttp://localhost:%d/%s/\n' % (8001, self._testdir_rel),
       'Full log for each test is here:\n',
       '\ttest/log/client_server_protocol_transport_client.log\n',
       '\ttest/log/client_server_protocol_transport_server.log\n',

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/test/crossrunner/run.py
----------------------------------------------------------------------
diff --git a/test/crossrunner/run.py b/test/crossrunner/run.py
index 32d166e..0d617c0 100644
--- a/test/crossrunner/run.py
+++ b/test/crossrunner/run.py
@@ -269,10 +269,11 @@ class NonAsyncResult(object):
 
 
 class TestDispatcher(object):
-  def __init__(self, testdir, logdir, concurrency):
+  def __init__(self, testdir, basedir, logdir_rel, concurrency):
     self._log = multiprocessing.get_logger()
     self.testdir = testdir
-    self.logdir = logdir
+    self._report = SummaryReporter(basedir, logdir_rel, concurrency > 1)
+    self.logdir = self._report.testdir
     # seems needed for python 2.x to handle keyboard interrupt
     self._stop = multiprocessing.Event()
     self._async = concurrency > 1
@@ -287,7 +288,6 @@ class TestDispatcher(object):
       self._m.register('ports', PortAllocator)
       self._m.start()
       self._pool = multiprocessing.Pool(concurrency, self._pool_init, (self._m.address,))
-    self._report = SummaryReporter(logdir, concurrency > 1)
     self._log.debug(
         'TestDispatcher started with %d concurrent jobs' % concurrency)
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/test/features/Makefile.am
----------------------------------------------------------------------
diff --git a/test/features/Makefile.am b/test/features/Makefile.am
new file mode 100644
index 0000000..f27af35
--- /dev/null
+++ b/test/features/Makefile.am
@@ -0,0 +1,27 @@
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+EXTRA_DIST = \
+	local_thrift \
+	index.html \
+	container_limit.py \
+	index.html \
+	known_failures_Linux.json \
+	Makefile.am \
+	string_limit.py \
+	tests.json \
+	theader_binary.py \
+	util.py

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/test/features/index.html
----------------------------------------------------------------------
diff --git a/test/features/index.html b/test/features/index.html
new file mode 100644
index 0000000..34a0010
--- /dev/null
+++ b/test/features/index.html
@@ -0,0 +1,51 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Apache Thrift - integration test suite</title>
+<link rel="stylesheet" type="text/css" href="http://cdn.datatables.net/1.10.4/css/jquery.dataTables.css">
+<script type="text/javascript" charset="utf-8" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
+<script type="text/javascript" charset="utf-8" src="http://cdn.datatables.net/1.10.4/js/jquery.dataTables.js"></script>
+<script src="../result.js">
+</script>
+</head>
+<body>
+<h2>Apache Thrift - integration test suite: Results</h2>
+<table id="test_results" class="display">
+    <thead>
+        <tr>
+            <th>Server</th>
+            <th>Client</th>
+            <th>Protocol</th>
+            <th>Transport</th>
+            <th>Result (log)</th>
+            <th>Expected</th>
+        </tr>
+    </thead>
+</table>
+<h2>Test Information</h2>
+<pre id="test_info"></pre>
+
+<a href="log">browse raw log files</a>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/test/index.html
----------------------------------------------------------------------
diff --git a/test/index.html b/test/index.html
new file mode 100644
index 0000000..3611a92
--- /dev/null
+++ b/test/index.html
@@ -0,0 +1,51 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Apache Thrift - integration test suite</title>
+<link rel="stylesheet" type="text/css" href="http://cdn.datatables.net/1.10.4/css/jquery.dataTables.css">
+<script type="text/javascript" charset="utf-8" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
+<script type="text/javascript" charset="utf-8" src="http://cdn.datatables.net/1.10.4/js/jquery.dataTables.js"></script>
+<script src="result.js">
+</script>
+</head>
+<body>
+<h2>Apache Thrift - integration test suite: Results</h2>
+<table id="test_results" class="display">
+    <thead>
+        <tr>
+            <th>Server</th>
+            <th>Client</th>
+            <th>Protocol</th>
+            <th>Transport</th>
+            <th>Result (log)</th>
+            <th>Expected</th>
+        </tr>
+    </thead>
+</table>
+<h2>Test Information</h2>
+<pre id="test_info"></pre>
+
+<a href="log">browse raw log</a>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/test/result.html
----------------------------------------------------------------------
diff --git a/test/result.html b/test/result.html
deleted file mode 100644
index 0f918be..0000000
--- a/test/result.html
+++ /dev/null
@@ -1,91 +0,0 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
-
--->
-<!DOCTYPE HTML>
-<html>
-<head>
-<meta charset="utf-8">
-<title>Apache Thrift - integration test suite</title>
-<link rel="stylesheet" type="text/css" href="http://cdn.datatables.net/1.10.4/css/jquery.dataTables.css">
-<script type="text/javascript" charset="utf-8" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
-<script type="text/javascript" charset="utf-8" src="http://cdn.datatables.net/1.10.4/js/jquery.dataTables.js"></script>
-<script>
-$.getJSON('results.json', function(results) {
-    $(document).ready(function() {
-        var transport = 3;
-        var socket = 4;
-        var success = 5;
-        var expected = 6;
-        var returnCode = 7;
-        var logFile = 8;
-        testTable = $('#test_results').DataTable({
-            data: results['results'],
-            columnDefs: [
-                {
-                    targets: 3,
-                    render: function(data, type, row) {
-                        return row[transport] + '-' + row[socket];
-                    },
-                },
-                {
-                    targets: 4,
-                    render: function(data, type, row) {
-                        return (row[success] ? 'success' : 'failure')
-                                + '(' + (row[returnCode] == 128 ? 'timeout' : row[returnCode]) + ')'
-                                + '(<a href="' + row[logFile].server + '">Server</a>, '
-                                + '<a href="' + row[logFile].client + '">Client</a>)';
-                    },
-                },
-                {
-                    targets: 5,
-                    render: function(data, type, row) {
-                        // 'yes' rather than 'expected' to ease search
-                        return row[expected] ? 'yes' : 'unexpected';
-                    },
-                }
-            ],
-        });
-        $('#test_results_filter label input').focus().val('unexpected failure');
-        $('#test_info').text(
-            "Test Date:     " + results['date'] + "\n" +
-            "Revision:      " + results['revision'] + "\n" +
-            "Platform:      " + results['platform'] + "\n" +
-            "Test duration: " + results['duration']) + " seconds";
-    });
-});
-</script>
-</head>
-<body>
-<h2>Apache Thrift - integration test suite: Results</h2>
-<table id="test_results" class="display">
-    <thead>
-        <tr>
-            <th>Server</th>
-            <th>Client</th>
-            <th>Protocol</th>
-            <th>Transport</th>
-            <th>Result (log)</th>
-            <th>Expected</th>
-        </tr>
-    </thead>
-</table>
-<h2>Test Information</h2>
-<pre id="test_info"></pre>
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/test/result.js
----------------------------------------------------------------------
diff --git a/test/result.js b/test/result.js
new file mode 100644
index 0000000..18b1a59
--- /dev/null
+++ b/test/result.js
@@ -0,0 +1,64 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+*/
+
+$.getJSON('results.json', function(results) {
+    $(document).ready(function() {
+        var transport = 3;
+        var socket = 4;
+        var success = 5;
+        var expected = 6;
+        var returnCode = 7;
+        var logFile = 8;
+        testTable = $('#test_results').DataTable({
+            data: results['results'],
+            columnDefs: [
+                {
+                    targets: 3,
+                    render: function(data, type, row) {
+                        return row[transport] + '-' + row[socket];
+                    },
+                },
+                {
+                    targets: 4,
+                    render: function(data, type, row) {
+                        return (row[success] ? 'success' : 'failure')
+                                + '(' + (row[returnCode] == 128 ? 'timeout' : row[returnCode]) + ')'
+                                + '(<a href="' + row[logFile].server + '">Server</a>, '
+                                + '<a href="' + row[logFile].client + '">Client</a>)';
+                    },
+                },
+                {
+                    targets: 5,
+                    render: function(data, type, row) {
+                        // 'yes' rather than 'expected' to ease search
+                        return row[expected] ? 'yes' : 'unexpected';
+                    },
+                }
+            ],
+        });
+        $('#test_results_filter label input').focus().val('unexpected failure');
+        $('#test_info').text(
+            "Test Date:     " + results['date'] + "\n" +
+            "Revision:      " + results['revision'] + "\n" +
+            "Platform:      " + results['platform'] + "\n" +
+            "Test duration: " + results['duration']) + " seconds";
+    });
+});
+

http://git-wip-us.apache.org/repos/asf/thrift/blob/bd165305/test/test.py
----------------------------------------------------------------------
diff --git a/test/test.py b/test/test.py
index 20d76f4..df4c72e 100755
--- a/test/test.py
+++ b/test/test.py
@@ -38,40 +38,13 @@ import sys
 import crossrunner
 from crossrunner.compat import path_join
 
-TEST_DIR = os.path.realpath(os.path.dirname(__file__))
-FEATURE_DIR = path_join(TEST_DIR, 'features')
+ROOT_DIR = os.path.dirname(os.path.realpath(os.path.dirname(__file__)))
+TEST_DIR_RELATIVE = 'test'
+TEST_DIR = path_join(ROOT_DIR, TEST_DIR_RELATIVE)
+FEATURE_DIR_RELATIVE = path_join(TEST_DIR_RELATIVE, 'features')
 CONFIG_FILE = 'tests.json'
 
 
-def run_tests(collect_func, basedir, server_match, client_match, jobs, skip):
-  logger = multiprocessing.get_logger()
-  logger.debug('Collecting tests')
-  with open(path_join(basedir, CONFIG_FILE), 'r') as fp:
-    j = json.load(fp)
-  tests = collect_func(j, server_match, client_match)
-  if not tests:
-    print('No test found that matches the criteria', file=sys.stderr)
-    # print('  servers: %s' % server_match, file=sys.stderr)
-    # print('  clients: %s' % client_match, file=sys.stderr)
-    return False
-  if skip:
-    logger.debug('Skipping known failures')
-    known = crossrunner.load_known_failures(basedir)
-    tests = list(filter(lambda t: crossrunner.test_name(**t) not in known, tests))
-
-  dispatcher = crossrunner.TestDispatcher(TEST_DIR, basedir, jobs)
-  logger.debug('Executing %d tests' % len(tests))
-  try:
-    for r in [dispatcher.dispatch(test) for test in tests]:
-      r.wait()
-    logger.debug('Waiting for completion')
-    return dispatcher.wait()
-  except (KeyboardInterrupt, SystemExit):
-    logger.debug('Interrupted, shutting down')
-    dispatcher.terminate()
-    return False
-
-
 def run_cross_tests(server_match, client_match, jobs, skip_known_failures):
   logger = multiprocessing.get_logger()
   logger.debug('Collecting tests')
@@ -88,7 +61,7 @@ def run_cross_tests(server_match, client_match, jobs, skip_known_failures):
     known = crossrunner.load_known_failures(TEST_DIR)
     tests = list(filter(lambda t: crossrunner.test_name(**t) not in known, tests))
 
-  dispatcher = crossrunner.TestDispatcher(TEST_DIR, TEST_DIR, jobs)
+  dispatcher = crossrunner.TestDispatcher(TEST_DIR, ROOT_DIR, TEST_DIR_RELATIVE, jobs)
   logger.debug('Executing %d tests' % len(tests))
   try:
     for r in [dispatcher.dispatch(test) for test in tests]:
@@ -102,7 +75,7 @@ def run_cross_tests(server_match, client_match, jobs, skip_known_failures):
 
 
 def run_feature_tests(server_match, feature_match, jobs, skip_known_failures):
-  basedir = FEATURE_DIR
+  basedir = path_join(ROOT_DIR, FEATURE_DIR_RELATIVE)
   logger = multiprocessing.get_logger()
   logger.debug('Collecting tests')
   with open(path_join(TEST_DIR, CONFIG_FILE), 'r') as fp:
@@ -120,7 +93,7 @@ def run_feature_tests(server_match, feature_match, jobs, skip_known_failures):
     known = crossrunner.load_known_failures(basedir)
     tests = list(filter(lambda t: crossrunner.test_name(**t) not in known, tests))
 
-  dispatcher = crossrunner.TestDispatcher(TEST_DIR, basedir, jobs)
+  dispatcher = crossrunner.TestDispatcher(TEST_DIR, ROOT_DIR, FEATURE_DIR_RELATIVE, jobs)
   logger.debug('Executing %d tests' % len(tests))
   try:
     for r in [dispatcher.dispatch(test) for test in tests]:
@@ -179,7 +152,7 @@ def main(argv):
   client_match = list(chain(*[x.split(',') for x in options.client]))
 
   if options.update_failures or options.print_failures:
-    dire = FEATURE_DIR if options.features is not None else TEST_DIR
+    dire = path_join(ROOT_DIR, FEATURE_DIR_RELATIVE) if options.features is not None else TEST_DIR
     res = crossrunner.generate_known_failures(
         dire, options.update_failures == 'overwrite',
         options.update_failures, options.print_failures)