Index: tools/testing/architecture.py |
diff --git a/tools/testing/architecture.py b/tools/testing/architecture.py |
index 7628ab2e1efb76a83baaac8f60dd816c935858db..8052c5e2a55137b7f0769d303584f2a306c380c5 100755 |
--- a/tools/testing/architecture.py |
+++ b/tools/testing/architecture.py |
@@ -1,30 +1,31 @@ |
-#!/usr/bin/env python |
-# |
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
# for details. All rights reserved. Use of this source code is governed by a |
# BSD-style license that can be found in the LICENSE file. |
# |
-""" |
-Runs a Dart unit test in different configurations: dartium, chromium, ia32, x64, |
-arm, simarm, and dartc. Example: |
+"""Runs a Dart unit test in different configurations. |
+ |
+Currently supported architectures include dartium, chromium, ia32, x64, |
+arm, simarm, and dartc. |
+ |
+Example: |
+ run.py --arch=dartium --mode=release --test=Test.dart |
-run.py --arch=dartium --mode=release --test=Test.dart |
""" |
import os |
-from os.path import join, abspath, dirname, basename, relpath |
import platform |
import re |
import shutil |
import subprocess |
import sys |
import tempfile |
+ |
import utils |
OS_GUESS = utils.GuessOS() |
-HTML_CONTENTS = ''' |
+HTML_CONTENTS = """ |
<html> |
<head> |
<title> Test %(title)s </title> |
@@ -52,14 +53,14 @@ HTML_CONTENTS = ''' |
</script> |
</body> |
</html> |
-''' |
+""" |
-DART_TEST_AS_LIBRARY = ''' |
+DART_TEST_AS_LIBRARY = """ |
#library('test'); |
#source('%(test)s'); |
-''' |
+""" |
-DART_CONTENTS = ''' |
+DART_CONTENTS = """ |
#library('test'); |
#import('%(dom_library)s'); |
@@ -101,49 +102,56 @@ main() { |
fail(e, trace); |
} |
} |
-''' |
+""" |
# Patterns for matching test options in .dart files. |
-VM_OPTIONS_PATTERN = re.compile(r"// VMOptions=(.*)") |
-DART_OPTIONS_PATTERN = re.compile(r"// DartOptions=(.*)") |
+VM_OPTIONS_PATTERN = re.compile(r'// VMOptions=(.*)') |
+DART_OPTIONS_PATTERN = re.compile(r'// DartOptions=(.*)') |
# Pattern for checking if the test is a web test. |
-DOM_IMPORT_PATTERN = re.compile(r"^#import.*(dart:dom|html.dart)'\);", |
+DOM_IMPORT_PATTERN = re.compile(r'#import.*(dart:dom|html.dart).*\);', |
re.MULTILINE) |
# Pattern for matching the output of a browser test. |
-BROWSER_OUTPUT_PASS_PATTERN = re.compile(r"^Content-Type: text/plain\nPASS$", |
+BROWSER_OUTPUT_PASS_PATTERN = re.compile(r'^Content-Type: text/plain\nPASS$', |
re.MULTILINE) |
# Pattern for checking if the test is a library in itself. |
-LIBRARY_DEFINITION_PATTERN = re.compile(r"^#library\(.*\);", |
+LIBRARY_DEFINITION_PATTERN = re.compile(r'^#library\(.*\);', |
re.MULTILINE) |
-SOURCE_OR_IMPORT_PATTERN = re.compile(r"^#(source|import)\(.*\);", |
+SOURCE_OR_IMPORT_PATTERN = re.compile(r'^#(source|import)\(.*\);', |
re.MULTILINE) |
class Error(Exception): |
+ """Base class for exceptions in this module.""" |
pass |
-def IsWebTest(test, source): |
+def _IsWebTest(source): |
+ """Returns True if the source includes a dart dom library #import.""" |
return DOM_IMPORT_PATTERN.search(source) |
+ |
def IsLibraryDefinition(test, source): |
- if LIBRARY_DEFINITION_PATTERN.search(source): return True |
+ """Returns True if the source has a #library statement.""" |
+ if LIBRARY_DEFINITION_PATTERN.search(source): |
+ return True |
if SOURCE_OR_IMPORT_PATTERN.search(source): |
- print ("WARNING for %s: Browser tests need a #library " |
- "for a file that #import or #source" % test) |
+ print ('WARNING for %s: Browser tests need a #library ' |
+ 'for a file that #import or #source' % test) |
return False |
class Architecture(object): |
+ """Definitions for different ways to test based on the --arch flag.""" |
+ |
def __init__(self, root_path, arch, mode, test): |
- self.root_path = root_path; |
- self.arch = arch; |
- self.mode = mode; |
- self.test = test; |
+ self.root_path = root_path |
+ self.arch = arch |
+ self.mode = mode |
+ self.test = test |
self.build_root = utils.GetBuildRoot(OS_GUESS, self.mode, self.arch) |
source = file(test).read() |
self.vm_options = utils.ParseTestOptions(VM_OPTIONS_PATTERN, |
@@ -154,77 +162,96 @@ class Architecture(object): |
self.dart_options = utils.ParseTestOptions(DART_OPTIONS_PATTERN, |
source, |
root_path) |
- self.is_web_test = IsWebTest(test, source) |
+ self.is_web_test = _IsWebTest(source) |
self.temp_dir = None |
def HasFatalTypeErrors(self): |
+ """Returns True if this type of arch supports --fatal-type-errors.""" |
return False |
def GetTestFrameworkPath(self): |
- return join(self.root_path, 'tests', 'isolate', 'src', |
- 'TestFramework.dart') |
+ """Path to dart source (TestFramework.dart) for testing framework.""" |
+ return os.path.join(self.root_path, 'tests', 'isolate', 'src', |
+ 'TestFramework.dart') |
+ |
class BrowserArchitecture(Architecture): |
+ """Architecture that runs compiled dart->JS through a browser.""" |
+ |
def __init__(self, root_path, arch, mode, test): |
super(BrowserArchitecture, self).__init__(root_path, arch, mode, test) |
- self.temp_dir = tempfile.mkdtemp(); |
+ self.temp_dir = tempfile.mkdtemp() |
if not self.is_web_test: self.GenerateWebTestScript() |
def GetTestScriptFile(self): |
"""Returns the name of the .dart file to compile.""" |
- if self.is_web_test: return abspath(self.test) |
- return join(self.temp_dir, 'test.dart') |
+ if self.is_web_test: return os.path.abspath(self.test) |
+ return os.path.join(self.temp_dir, 'test.dart') |
def GetHtmlContents(self): |
+ """Fills in the HTML_CONTENTS template with info for this architecture.""" |
script_type = self.GetScriptType() |
+ controller_path = os.path.join(self.root_path, 'client', 'testing', |
+ 'unittest', 'test_controller.js') |
+ return HTML_CONTENTS % { |
+ 'title': self.test, |
+ 'controller_script': controller_path, |
+ 'script_type': script_type, |
+ 'source_script': self.GetScriptPath() |
+ } |
- controller_path = join(self.root_path, |
- 'client', 'testing', 'unittest', 'test_controller.js') |
+ def GetHtmlPath(self): |
+ """Creates a path for the generated .html file. |
- return HTML_CONTENTS % { 'title' : self.test, |
- 'controller_script': controller_path, |
- 'script_type' : script_type, |
- 'source_script' : self.GetScriptPath() } |
+ Resources for web tests are relative to the 'html' file. We |
+ output the 'html' file in the 'out' directory instead of the temporary |
+ directory because we can easily go the the resources in 'client' through |
+ 'out'. |
- def GetHtmlPath(self): |
- # Resources for web tests are relative to the 'html' file. We |
- # output the 'html' file in the 'out' directory instead of the temporary |
- # directory because we can easily go the the resources in 'client' through |
- # 'out'. |
+ Returns: |
+ Created path for the generated .html file. |
+ """ |
if self.is_web_test: |
- html_path = join(self.root_path, 'client', self.build_root) |
- if not os.path.exists(html_path): os.makedirs(html_path) |
+ html_path = os.path.join(self.root_path, 'client', self.build_root) |
+ if not os.path.exists(html_path): |
+ os.makedirs(html_path) |
return html_path |
return self.temp_dir |
def GetTestContents(self, library_file): |
- unittest_path = join(self.root_path, |
- 'client', 'testing', 'unittest', 'unittest.dart') |
+ """Pastes a preamble on the front of the .dart file before testing.""" |
+ unittest_path = os.path.join(self.root_path, 'client', 'testing', |
+ 'unittest', 'unittest.dart') |
+ |
if self.arch == 'chromium': |
- dom_path = join(self.root_path, |
- 'client', 'testing', 'unittest', 'dom_for_unittest.dart') |
+ dom_path = os.path.join(self.root_path, 'client', 'testing', |
+ 'unittest', 'dom_for_unittest.dart') |
else: |
- dom_path = join('dart:dom') |
+ dom_path = os.path.join('dart:dom') |
test_framework_path = self.GetTestFrameworkPath() |
- test_name = basename(self.test) |
- test_path = abspath(self.test) |
- |
- inputs = { 'unittest': unittest_path, |
- 'test': test_path, |
- 'dom_library': dom_path, |
- 'test_framework': test_framework_path, |
- 'library': library_file } |
+ test_path = os.path.abspath(self.test) |
+ |
+ inputs = { |
+ 'unittest': unittest_path, |
+ 'test': test_path, |
+ 'dom_library': dom_path, |
+ 'test_framework': test_framework_path, |
+ 'library': library_file |
+ } |
return DART_CONTENTS % inputs |
def GenerateWebTestScript(self): |
+ """Creates a .dart file to run in the test.""" |
if IsLibraryDefinition(self.test, file(self.test).read()): |
- library_file = abspath(self.test) |
+ library_file = os.path.abspath(self.test) |
else: |
library_file = 'test_as_library.dart' |
- test_as_library = DART_TEST_AS_LIBRARY % { 'test': abspath(self.test) } |
- test_as_library_file = join(self.temp_dir, library_file) |
+ test_as_library = DART_TEST_AS_LIBRARY % { |
+ 'test': os.path.abspath(self.test) |
+ } |
+ test_as_library_file = os.path.join(self.temp_dir, library_file) |
f = open(test_as_library_file, 'w') |
f.write(test_as_library) |
f.close() |
@@ -234,16 +261,18 @@ class BrowserArchitecture(Architecture): |
f.write(self.GetTestContents(library_file)) |
f.close() |
- def GetRunCommand(self, fatal_static_type_errors = False): |
+ def GetRunCommand(self, fatal_static_type_errors=False): |
+ """Returns a command line to execute for the test.""" |
+ fatal_static_type_errors = fatal_static_type_errors # shutup lint! |
# For some reason, DRT needs to be called via an absolute path |
- drt_location = join(self.root_path, |
- 'client', 'tests', 'drt', 'DumpRenderTree') |
+ drt_location = os.path.join(self.root_path, 'client', 'tests', 'drt', |
+ 'DumpRenderTree') |
# On Mac DumpRenderTree is a .app folder |
if platform.system() == 'Darwin': |
drt_location += '.app/Contents/MacOS/DumpRenderTree' |
- drt_flags = [ '--no-timeout' ] |
+ drt_flags = ['--no-timeout'] |
dart_flags = '--dart-flags=--enable_asserts --enable_type_checks ' |
dart_flags += ' '.join(self.vm_options) |
@@ -251,7 +280,7 @@ class BrowserArchitecture(Architecture): |
dart_flags += ' --optimize ' |
drt_flags.append(dart_flags) |
- html_output_file = join(self.GetHtmlPath(), self.GetHtmlName()) |
+ html_output_file = os.path.join(self.GetHtmlPath(), self.GetHtmlName()) |
f = open(html_output_file, 'w') |
f.write(self.GetHtmlContents()) |
f.close() |
@@ -261,22 +290,32 @@ class BrowserArchitecture(Architecture): |
return [drt_location] + drt_flags |
def HasFailed(self, output): |
+ """Return True if the 'PASS' result string isn't in the output.""" |
return not BROWSER_OUTPUT_PASS_PATTERN.search(output) |
def RunTest(self, verbose): |
+ """Calls GetRunCommand() and executes the returned commandline. |
+ |
+ Args: |
+ verbose: if True, print additional diagnostics to stdout. |
+ |
+ Returns: |
+ Return code from executable. 0 == PASS, 253 = CRASH, anything |
+ else is treated as FAIL |
+ """ |
retcode = self.Compile() |
if retcode != 0: return 1 |
command = self.GetRunCommand() |
- status, output, err = ExecutePipedCommand(command, verbose) |
+ unused_status, output, err = ExecutePipedCommand(command, verbose) |
if not self.HasFailed(output): |
self.Cleanup() |
return 0 |
# TODO(sigmund): print better error message, including how to run test |
# locally, and translate error traces using source map info. |
- print "(FAIL) test page:\033[31m " + command[2] + " \033[0m" |
+ print '(FAIL) test page:\033[31m %s \033[0m' % command[2] |
if verbose: |
print 'Additional info: ' |
print output |
@@ -284,12 +323,15 @@ class BrowserArchitecture(Architecture): |
return 1 |
def Cleanup(self): |
+ """Removes temporary files created for the test.""" |
if self.temp_dir: |
shutil.rmtree(self.temp_dir) |
self.temp_dir = None |
class ChromiumArchitecture(BrowserArchitecture): |
+ """Architecture that runs compiled dart->JS through a chromium DRT.""" |
+ |
def __init__(self, root_path, arch, mode, test): |
super(ChromiumArchitecture, self).__init__(root_path, arch, mode, test) |
@@ -297,29 +339,30 @@ class ChromiumArchitecture(BrowserArchitecture): |
return 'text/javascript' |
def GetScriptPath(self): |
- """ Returns the name of the output .js file to create """ |
+ """Returns the name of the output .js file to create.""" |
path = self.GetTestScriptFile() |
- return abspath(os.path.join(self.temp_dir, |
- os.path.basename(path) + '.js')) |
- |
+ return os.path.abspath(os.path.join(self.temp_dir, |
+ os.path.basename(path) + '.js')) |
def GetHtmlName(self): |
- return relpath(self.test, self.root_path).replace(os.sep, '_') + '.html' |
+ """Returns the name of the output .html file to create.""" |
+ relpath = os.path.relpath(self.test, self.root_path) |
+ return relpath.replace(os.sep, '_') + '.html' |
def GetCompileCommand(self, fatal_static_type_errors=False): |
- """ Returns cmdline as an array to invoke the compiler on this test""" |
+ """Returns cmdline as an array to invoke the compiler on this test.""" |
+ |
# We need an absolute path because the compilation will run |
# in a temporary directory. |
- |
- dartc = abspath(join(utils.GetBuildRoot(OS_GUESS, self.mode, 'dartc'), |
- 'compiler', |
- 'bin', |
- 'dartc')) |
+ build_root = utils.GetBuildRoot(OS_GUESS, self.mode, 'dartc') |
+ dartc = os.path.abspath(os.path.join(build_root, 'compiler', 'bin', |
+ 'dartc')) |
if utils.IsWindows(): dartc += '.exe' |
cmd = [dartc, '--work', self.temp_dir] |
cmd += self.vm_options |
cmd += ['--out', self.GetScriptPath()] |
if fatal_static_type_errors: |
+ # TODO(zundel): update to --fatal_type_errors for both VM and Compiler |
cmd.append('-fatal-type-errors') |
cmd.append(self.GetTestScriptFile()) |
return cmd |
@@ -329,6 +372,8 @@ class ChromiumArchitecture(BrowserArchitecture): |
class DartiumArchitecture(BrowserArchitecture): |
+ """Architecture that runs dart in an VM embedded in DumpRenderTree.""" |
+ |
def __init__(self, root_path, arch, mode, test): |
super(DartiumArchitecture, self).__init__(root_path, arch, mode, test) |
@@ -339,10 +384,11 @@ class DartiumArchitecture(BrowserArchitecture): |
return 'file:///' + self.GetTestScriptFile() |
def GetHtmlName(self): |
- path = relpath(self.test, self.root_path).replace(os.sep, '_') |
+ path = os.path.relpath(self.test, self.root_path).replace(os.sep, '_') |
return path + '.dartium.html' |
def GetCompileCommand(self, fatal_static_type_errors=False): |
+ fatal_static_type_errors = fatal_static_type_errors # shutup lint! |
return None |
def Compile(self): |
@@ -350,25 +396,29 @@ class DartiumArchitecture(BrowserArchitecture): |
class StandaloneArchitecture(Architecture): |
+ """Base class for architectures that run tests without a browser.""" |
+ |
def __init__(self, root_path, arch, mode, test): |
super(StandaloneArchitecture, self).__init__(root_path, arch, mode, test) |
def GetCompileCommand(self, fatal_static_type_errors=False): |
+ fatal_static_type_errors = fatal_static_type_errors # shutup lint! |
return None |
def GetRunCommand(self, fatal_static_type_errors=False): |
+ """Returns a command line to execute for the test.""" |
dart = self.GetExecutable() |
- test_name = basename(self.test) |
- test_path = abspath(self.test) |
+ test_name = os.path.basename(self.test) |
+ test_path = os.path.abspath(self.test) |
command = [dart] + self.vm_options |
(classname, extension) = os.path.splitext(test_name) |
if self.dart_options: |
command += self.dart_options |
- elif (extension == '.dart'): |
+ elif extension == '.dart': |
if fatal_static_type_errors: |
command += self.GetFatalTypeErrorsFlags() |
if '_' in classname: |
- (classname, sep, tag) = classname.rpartition('_') |
+ (classname, unused_sep, unused_tag) = classname.rpartition('_') |
command += [test_path] |
else: |
command += ['--', test_path] |
@@ -389,11 +439,17 @@ class StandaloneArchitecture(Architecture): |
# Long term, we should do the running machinery that is currently in |
# DartRunner.java |
class DartcArchitecture(StandaloneArchitecture): |
+ """Runs the Dart ->JS compiler then runs the result in a standalone JS VM.""" |
+ |
def __init__(self, root_path, arch, mode, test): |
super(DartcArchitecture, self).__init__(root_path, arch, mode, test) |
def GetExecutable(self): |
- return abspath(join(self.build_root, 'compiler', 'bin', 'dartc_test')) |
+ """Returns the name of the executable to run the test.""" |
+ return os.path.abspath(os.path.join(self.build_root, |
+ 'compiler', |
+ 'bin', |
+ 'dartc_test')) |
def GetFatalTypeErrorsFlags(self): |
return ['--fatal-type-errors'] |
@@ -402,23 +458,27 @@ class DartcArchitecture(StandaloneArchitecture): |
return True |
def GetRunCommand(self, fatal_static_type_errors=False): |
+ """Returns a command line to execute for the test.""" |
cmd = super(DartcArchitecture, self).GetRunCommand( |
fatal_static_type_errors) |
return cmd |
class RuntimeArchitecture(StandaloneArchitecture): |
+ """Executes tests on the standalone VM (runtime).""" |
+ |
def __init__(self, root_path, arch, mode, test): |
super(RuntimeArchitecture, self).__init__(root_path, arch, mode, test) |
def GetExecutable(self): |
- return abspath(join(self.build_root, 'dart_bin')) |
+ """Returns the name of the executable to run the test.""" |
+ return os.path.abspath(os.path.join(self.build_root, 'dart_bin')) |
def ExecutePipedCommand(cmd, verbose): |
- """Execute a command in a subprocess. |
- """ |
- if verbose: print 'Executing: ' + ' '.join(cmd) |
+ """Execute a command in a subprocess.""" |
+ if verbose: |
+ print 'Executing: ' + ' '.join(cmd) |
pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
(output, err) = pipe.communicate() |
if pipe.returncode != 0 and verbose: |
@@ -428,15 +488,14 @@ def ExecutePipedCommand(cmd, verbose): |
return pipe.returncode, output, err |
-def ExecuteCommand(cmd, verbose = False): |
- """Execute a command in a subprocess. |
- """ |
+def ExecuteCommand(cmd, verbose=False): |
+ """Execute a command in a subprocess.""" |
if verbose: print 'Executing: ' + ' '.join(cmd) |
return subprocess.call(cmd) |
def GetArchitecture(arch, mode, test): |
- root_path = abspath(join(dirname(sys.argv[0]), '..')) |
+ root_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..')) |
if arch == 'chromium': |
return ChromiumArchitecture(root_path, arch, mode, test) |
@@ -448,4 +507,3 @@ def GetArchitecture(arch, mode, test): |
elif arch == 'dartc': |
return DartcArchitecture(root_path, arch, mode, test) |
- |