diff --git a/test/message/testcfg.py b/test/message/testcfg.py
index df2cbf3150e..85fb6651c9c 100644
--- a/test/message/testcfg.py
+++ b/test/message/testcfg.py
@@ -25,127 +25,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-import test
-import os
-from os.path import join, exists, basename, isdir
-import re
-
-FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
-
-class MessageTestCase(test.TestCase):
-
-  def __init__(self, path, file, expected, arch, mode, context, config):
-    super(MessageTestCase, self).__init__(context, path, arch, mode)
-    self.file = file
-    self.expected = expected
-    self.config = config
-    self.arch = arch
-    self.mode = mode
-
-  def IgnoreLine(self, str):
-    """Ignore empty lines and valgrind output."""
-    if not str.strip(): return True
-    else: return str.startswith('==') or str.startswith('**')
-
-  def IsFailureOutput(self, output):
-    f = file(self.expected)
-    # Skip initial '#' comment and spaces
-    #for line in f:
-    #  if (not line.startswith('#')) and (not line.strip()):
-    #    break
-    # Convert output lines to regexps that we can match
-    env = { 'basename': basename(self.file) }
-    patterns = [ ]
-    for line in f:
-      if not line.strip():
-        continue
-      pattern = re.escape(line.rstrip() % env)
-      pattern = pattern.replace('\\*', '.*')
-      pattern = '^%s$' % pattern
-      patterns.append(pattern)
-    # Compare actual output with the expected
-    raw_lines = (output.stdout + output.stderr).split('\n')
-    outlines = [ s for s in raw_lines if not self.IgnoreLine(s) ]
-    if len(outlines) != len(patterns):
-      print "length differs."
-      print "expect=%d" % len(patterns)
-      print "actual=%d" % len(outlines)
-      print "patterns:"
-      for i in xrange(len(patterns)):
-        print "pattern = %s" % patterns[i]
-      print "outlines:"
-      for i in xrange(len(outlines)):
-        print "outline = %s" % outlines[i]
-      return True
-    for i in xrange(len(patterns)):
-      if not re.match(patterns[i], outlines[i]):
-        print "match failed"
-        print "line=%d" % i
-        print "expect=%s" % patterns[i]
-        print "actual=%s" % outlines[i]
-        return True
-    return False
-
-  def GetLabel(self):
-    return "%s %s" % (self.mode, self.GetName())
-
-  def GetName(self):
-    return self.path[-1]
-
-  def GetCommand(self):
-    result = [self.config.context.GetVm(self.arch, self.mode)]
-    source = open(self.file).read()
-    flags_match = FLAGS_PATTERN.search(source)
-    if flags_match:
-      result += flags_match.group(1).strip().split()
-    result.append(self.file)
-    return result
-
-  def GetSource(self):
-    return (open(self.file).read()
-          + "\n--- expected output ---\n"
-          + open(self.expected).read())
-
-
-class MessageTestConfiguration(test.TestConfiguration):
-
-  def __init__(self, context, root):
-    super(MessageTestConfiguration, self).__init__(context, root)
-
-  def Ls(self, path):
-    if isdir(path):
-      return [f for f in os.listdir(path)
-              if f.endswith('.js') or f.endswith('.mjs')]
-    else:
-      return []
-
-  def ListTests(self, current_path, path, arch, mode, jsEngine):
-    all_tests = [current_path + [t] for t in self.Ls(self.root)]
-    result = []
-    for test in all_tests:
-      if self.Contains(path, test):
-        file_path = join(self.root, reduce(join, test[1:], ''))
-        file_prefix = file_path[:file_path.rfind('.')]
-        engine_output_path = file_prefix + (".%s.out" % jsEngine)
-        output_path = file_prefix + '.out'
-        if exists(engine_output_path):
-          output_path = engine_output_path
-        else:
-          if not exists(output_path):
-            raise Exception("Could not find %s" % output_path)
-
-        result.append(MessageTestCase(test, file_path, output_path,
-                                      arch, mode, self.context, self))
-    return result
-
-  def GetBuildRequirements(self):
-    return ['sample', 'sample=shell']
-
-  def GetTestStatus(self, sections, defs):
-    status_file = join(self.root, 'message.status')
-    if exists(status_file):
-      test.ReadConfigurationInto(status_file, sections, defs)
-
+import sys, os
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import testpy
 
 def GetConfiguration(context, root):
-  return MessageTestConfiguration(context, root)
+  return testpy.MessageTestConfiguration(context, root, 'message')
diff --git a/test/testpy/__init__.py b/test/testpy/__init__.py
index deb9e47fe9d..0487a6f3c33 100644
--- a/test/testpy/__init__.py
+++ b/test/testpy/__init__.py
@@ -27,7 +27,7 @@
 
 import test
 import os
-from os.path import join, dirname, exists, splitext
+from os.path import join, dirname, exists, splitext, isdir, basename
 import re
 import ast
 
@@ -49,7 +49,6 @@ def __init__(self, path, file, arch, mode, context, config, additional=None):
     else:
       self.additional_flags = []
 
-
   def GetLabel(self):
     return "%s %s" % (self.mode, self.GetName())
 
@@ -70,10 +69,10 @@ def GetCommand(self):
       # the '--inspect' flag cannot be passed to the node process as it will
       # cause node to exit and report the test as failed. The use case
       # is currently when Node is configured --without-ssl and the tests should
-      # still be runnable but skip any tests that require ssl (which includes the
-      # inspector related tests). Also, if there is no ssl support the options
-      # '--use-bundled-ca' and '--use-openssl-ca' will also cause a similar
-      # failure so such tests are also skipped.
+      # still be runnable but skip any tests that require ssl (which includes
+      # the inspector related tests). Also, if there is no ssl support the
+      # options '--use-bundled-ca' and '--use-openssl-ca' will also cause a
+      # similar failure so such tests are also skipped.
       if ('--inspect' in flag[0] or \
           '--use-bundled-ca' in flag[0] or \
           '--use-openssl-ca' in flag[0]) and \
@@ -98,6 +97,63 @@ def GetCommand(self):
   def GetSource(self):
     return open(self.file).read()
 
+class MessageTestCase(SimpleTestCase):
+
+  def __init__(self, path, file, arch, mode, context, config, expected,
+                                                        additional=None):
+    super(MessageTestCase, self).__init__(path, file, arch, mode, context,
+                                                        config, additional)
+    self.expected = expected
+
+  def IgnoreLine(self, str):
+    """Ignore empty lines and valgrind output."""
+    if not str.strip(): return True
+    else: return str.startswith('==') or str.startswith('**')
+
+  def IsFailureOutput(self, output):
+    f = file(self.expected)
+    # Skip initial '#' comment and spaces
+    #for line in f:
+    #  if (not line.startswith('#')) and (not line.strip()):
+    #    break
+    # Convert output lines to regexps that we can match
+    env = { 'basename': basename(self.file) }
+    patterns = [ ]
+    for line in f:
+      if not line.strip():
+        continue
+      pattern = re.escape(line.rstrip() % env)
+      pattern = pattern.replace('\\*', '.*')
+      pattern = '^%s$' % pattern
+      patterns.append(pattern)
+    # Compare actual output with the expected
+    raw_lines = (output.stdout + output.stderr).split('\n')
+    outlines = [ s for s in raw_lines if not self.IgnoreLine(s) ]
+    if len(outlines) != len(patterns):
+      print "length differs."
+      print "expect=%d" % len(patterns)
+      print "actual=%d" % len(outlines)
+      print "patterns:"
+      for i in xrange(len(patterns)):
+        print "pattern = %s" % patterns[i]
+      print "outlines:"
+      for i in xrange(len(outlines)):
+        print "outline = %s" % outlines[i]
+      return True
+    for i in xrange(len(patterns)):
+      if not re.match(patterns[i], outlines[i]):
+        print "match failed"
+        print "line=%d" % i
+        print "expect=%s" % patterns[i]
+        print "actual=%s" % outlines[i]
+        return True
+    return False
+
+  def GetSource(self):
+    return (open(self.file).read()
+          + "\n--- expected output ---\n"
+          + open(self.expected).read())
+
 class SimpleTestConfiguration(test.TestConfiguration):
 
   def __init__(self, context, root, section, additional=None):
@@ -144,7 +200,8 @@ def ListTests(self, current_path, path, arch, mode, jsEngine):
 
 class AddonTestConfiguration(SimpleTestConfiguration):
   def __init__(self, context, root, section, additional=None):
-    super(AddonTestConfiguration, self).__init__(context, root, section, additional)
+    super(AddonTestConfiguration, self).__init__(context, root, section,
+                                                    additional)
 
   def Ls(self, path):
     def SelectTest(name):
@@ -165,7 +222,8 @@ def ListTests(self, current_path, path, arch, mode, jsEngine):
       if self.Contains(path, test):
         file_path = join(self.root, reduce(join, test[1:], "") + ".js")
         result.append(
-            SimpleTestCase(test, file_path, arch, mode, self.context, self, self.additional_flags))
+            SimpleTestCase(test, file_path, arch, mode, self.context, self,
+                                                    self.additional_flags))
     return result
 
 class AsyncHooksTestConfiguration(SimpleTestConfiguration):
@@ -191,3 +249,34 @@ def ListTests(self, current_path, path, arch, mode, jsEngine):
     for test in result:
       test.disable_core_files = True
     return result
+
+class MessageTestConfiguration(SimpleTestConfiguration):
+  def __init__(self, context, root, section, additional=None):
+    super(MessageTestConfiguration, self).__init__(context, root, section,
+                                                 additional)
+
+  def Ls(self, path):
+    if isdir(path):
+      return [f for f in os.listdir(path)
+                                if f.endswith('.js') or f.endswith('.mjs')]
+    else:
+      return []
+
+  def ListTests(self, current_path, path, arch, mode, jsEngine):
+    all_tests = [current_path + [t] for t in self.Ls(join(self.root))]
+    result = []
+    for test in all_tests:
+      if self.Contains(path, test):
+        test_name = test[:-1] + [splitext(test[-1])[0]]
+        file_path = join(self.root, reduce(join, test[1:], ''))
+        file_prefix = file_path[:file_path.rfind('.')]
+        engine_output_path = file_prefix + (".%s.out" % jsEngine)
+        output_path = file_prefix + '.out'
+        if exists(engine_output_path):
+          output_path = engine_output_path
+        else:
+          if not exists(output_path):
+            raise Exception("Could not find %s" % output_path)
+        result.append(MessageTestCase(test_name, file_path, arch, mode,
+                           self.context, self, output_path, self.additional_flags))
+    return result