THRIFT-3452 .travis.yml: Migrating from legacy to container-based infrastructure
Client: Build
Patch: Nobuaki Sukegawa

Use "services: docker"

This closes #730
diff --git a/test/crossrunner/__init__.py b/test/crossrunner/__init__.py
index 06de2d0..584cc07 100644
--- a/test/crossrunner/__init__.py
+++ b/test/crossrunner/__init__.py
@@ -17,9 +17,8 @@
 # under the License.
 #
 
-from crossrunner.test import test_name
-from crossrunner.collect import collect_tests
-from crossrunner.run import TestDispatcher
-from crossrunner.report import generate_known_failures
-from crossrunner.report import load_known_failures
-from crossrunner.prepare import prepare
+from .test import test_name
+from .collect import collect_tests
+from .run import TestDispatcher
+from .report import generate_known_failures, load_known_failures
+from .prepare import prepare
diff --git a/test/crossrunner/collect.py b/test/crossrunner/collect.py
index 145afef..c6e33e9 100644
--- a/test/crossrunner/collect.py
+++ b/test/crossrunner/collect.py
@@ -20,7 +20,7 @@
 import platform
 from itertools import product
 
-from crossrunner.util import merge_dict
+from .util import merge_dict
 
 # Those keys are passed to execution as is.
 # Note that there are keys other than these, namely:
diff --git a/test/crossrunner/compat.py b/test/crossrunner/compat.py
index 70992f6..6ab9d71 100644
--- a/test/crossrunner/compat.py
+++ b/test/crossrunner/compat.py
@@ -13,9 +13,12 @@
     b = s.decode(_ENCODE)
     return b.join(bin_args).encode(_ENCODE)
 
+  logfile_open = open
+
 else:
 
   path_join = os.path.join
+  str_join = str.join
 
-  def str_join(s, l):
-    return s.join(l)
+  def logfile_open(*args):
+    return open(*args, errors='replace')
diff --git a/test/crossrunner/prepare.py b/test/crossrunner/prepare.py
index 6e4f6ee..c6784af 100644
--- a/test/crossrunner/prepare.py
+++ b/test/crossrunner/prepare.py
@@ -20,7 +20,7 @@
 import os
 import subprocess
 
-from crossrunner.collect import collect_testlibs
+from .collect import collect_testlibs
 
 
 def prepare(config_dict, testdir, server_match, client_match):
diff --git a/test/crossrunner/report.py b/test/crossrunner/report.py
index bcfe181..defc486 100644
--- a/test/crossrunner/report.py
+++ b/test/crossrunner/report.py
@@ -17,6 +17,7 @@
 # under the License.
 #
 
+from __future__ import print_function
 import datetime
 import json
 import multiprocessing
@@ -28,7 +29,7 @@
 import time
 import traceback
 
-from .compat import path_join, str_join
+from .compat import logfile_open, path_join, str_join
 from .test import TestEntry
 
 LOG_DIR = 'log'
@@ -44,7 +45,7 @@
       if not r[success_index]:
         yield TestEntry.get_name(*r)
   try:
-    with open(os.path.join(testdir, RESULT_JSON), 'r') as fp:
+    with logfile_open(os.path.join(testdir, RESULT_JSON), 'r') as fp:
       results = json.load(fp)
   except IOError:
     sys.stderr.write('Unable to load last result. Did you run tests ?\n')
@@ -67,7 +68,7 @@
 
 def load_known_failures(testdir):
   try:
-    with open(os.path.join(testdir, FAIL_JSON % platform.system()), 'r') as fp:
+    with logfile_open(os.path.join(testdir, FAIL_JSON % platform.system()), 'r') as fp:
       return json.load(fp)
   except IOError:
     return []
@@ -138,16 +139,7 @@
       self._lock.release()
 
   def killed(self):
-    self._lock.acquire()
-    try:
-      if self.out and not self.out.closed:
-        self._print_footer()
-        self._close()
-        self.out = None
-      else:
-        self._log.debug('Output stream is not available.')
-    finally:
-      self._lock.release()
+    self.end(None)
 
   _init_failure_exprs = {
     'server': list(map(re.compile, [
@@ -177,8 +169,7 @@
 
       server_logfile = self.logpath
       # need to handle unicode errors on Python 3
-      kwargs = {} if sys.version_info[0] < 3 else {'errors': 'replace'}
-      with open(server_logfile, 'r', **kwargs) as fp:
+      with logfile_open(server_logfile, 'r') as fp:
         if any(map(match, fp)):
           return True
     except (KeyboardInterrupt, SystemExit):
@@ -345,12 +336,12 @@
   def _assemble_log(self, title, indexes):
     if len(indexes) > 0:
       def add_prog_log(fp, test, prog_kind):
-        fp.write('*************************** %s message ***************************\n'
-                 % prog_kind)
+        print('*************************** %s message ***************************' % prog_kind,
+              file=fp)
         path = self.test_logfile(test.name, prog_kind, self.testdir)
-        kwargs = {} if sys.version_info[0] < 3 else {'errors': 'replace'}
-        with open(path, 'r', **kwargs) as prog_fp:
-          fp.write(prog_fp.read())
+        if os.path.exists(path):
+          with logfile_open(path, 'r') as prog_fp:
+            print(prog_fp.read(), file=fp)
       filename = title.replace(' ', '_') + '.log'
       with open(os.path.join(self.logdir, filename), 'w+') as fp:
         for test in map(self._tests.__getitem__, indexes):
@@ -358,7 +349,7 @@
           add_prog_log(fp, test, test.server.kind)
           add_prog_log(fp, test, test.client.kind)
           fp.write('**********************************************************************\n\n')
-      self.out.write('%s are logged to test/%s/%s\n' % (title.capitalize(), LOG_DIR, filename))
+      print('%s are logged to test/%s/%s' % (title.capitalize(), LOG_DIR, filename))
 
   def end(self):
     self._print_footer()
diff --git a/test/crossrunner/run.py b/test/crossrunner/run.py
index 129016c..acba335 100644
--- a/test/crossrunner/run.py
+++ b/test/crossrunner/run.py
@@ -21,15 +21,14 @@
 import multiprocessing
 import multiprocessing.managers
 import os
-import sys
 import platform
 import random
-import socket
 import signal
+import socket
 import subprocess
+import sys
 import threading
 import time
-import traceback
 
 from .compat import str_join
 from .test import TestEntry, domain_socket_path
@@ -165,10 +164,10 @@
     stop.set()
     return None
   except Exception as ex:
-    logger.warn('Error while executing test : %s' % str(ex))
+    logger.warn('%s', ex)
     if not async:
       raise
-    logger.info(traceback.print_exc())
+    logger.debug('Error executing [%s]', test.name, exc_info=sys.exc_info())
     return RESULT_ERROR
 
 
diff --git a/test/crossrunner/test.py b/test/crossrunner/test.py
index 63219e1..49ba7d3 100644
--- a/test/crossrunner/test.py
+++ b/test/crossrunner/test.py
@@ -22,8 +22,7 @@
 import os
 import sys
 from .compat import path_join
-
-from crossrunner.util import merge_dict
+from .util import merge_dict
 
 
 def domain_socket_path(port):