mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
Remove remaining traces of content_shell and DumpRenderTree
Change-Id: Iae15260fa588b101929095c865807efecfb678a2 Reviewed-on: https://dart-review.googlesource.com/71960 Reviewed-by: Jonas Termansen <sortie@google.com>
This commit is contained in:
parent
fa14dbcdfc
commit
3603bfaebd
14 changed files with 13 additions and 749 deletions
14
DEPS
14
DEPS
|
@ -402,20 +402,6 @@ hooks = [
|
|||
Var('dart_root') + "/third_party/firefox_jsshell",
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "drt_resources",
|
||||
"pattern": ".",
|
||||
"action": [
|
||||
"download_from_google_storage",
|
||||
"--no_auth",
|
||||
"--no_resume",
|
||||
"--bucket",
|
||||
"dart-dependencies",
|
||||
"--platform=win32",
|
||||
"--directory",
|
||||
Var('dart_root') + "/third_party/drt_resources",
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "7zip",
|
||||
"pattern": ".",
|
||||
|
|
1
third_party/.gitignore
vendored
1
third_party/.gitignore
vendored
|
@ -6,7 +6,6 @@
|
|||
!pkg
|
||||
!pkg_tested
|
||||
!/tcmalloc
|
||||
!drt_resources
|
||||
!d8
|
||||
!7zip.tar.gz.sha1
|
||||
!firefox_jsshell
|
||||
|
|
1
third_party/drt_resources/.gitignore
vendored
1
third_party/drt_resources/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
AHEM____.TTF
|
1
third_party/drt_resources/AHEM____.TTF.sha1
vendored
1
third_party/drt_resources/AHEM____.TTF.sha1
vendored
|
@ -1 +0,0 @@
|
|||
8cdc9e68594fbb6db8c7b4bff643ab2432b51db6
|
6
third_party/drt_resources/README.md
vendored
6
third_party/drt_resources/README.md
vendored
|
@ -1,6 +0,0 @@
|
|||
# Content-shell resources
|
||||
|
||||
The layout tests of content_shell (formerly called DumpRenderTree, drt)
|
||||
require a font called AHEM____.TTF on Windows. This resource is downloaded
|
||||
from cloud storage, using the hash in AHEM____.TTF.sha1, by a hook
|
||||
in the DEPS file, that is run by gclient sync or gclient runhooks.
|
|
@ -1,342 +0,0 @@
|
|||
#!/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.
|
||||
|
||||
# Gets or updates a content shell (a nearly headless build of chrome). This is
|
||||
# used for running browser tests of client applications.
|
||||
|
||||
import json
|
||||
import optparse
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import zipfile
|
||||
|
||||
import utils
|
||||
|
||||
def NormJoin(path1, path2):
|
||||
return os.path.normpath(os.path.join(path1, path2))
|
||||
|
||||
# Change into the dart directory as we want the project to be rooted here.
|
||||
dart_src = NormJoin(os.path.dirname(sys.argv[0]), os.pardir)
|
||||
os.chdir(dart_src)
|
||||
|
||||
GSUTIL_DIR = os.path.join('third_party', 'gsutil')
|
||||
GSUTIL = GSUTIL_DIR + '/gsutil'
|
||||
|
||||
DRT_DIR = os.path.join('client', 'tests', 'drt')
|
||||
DRT_VERSION = os.path.join(DRT_DIR, 'LAST_VERSION')
|
||||
DRT_LATEST_PATTERN = (
|
||||
'gs://dartium-archive/latest/drt-%(osname)s-%(bot)s-*.zip')
|
||||
DRT_PERMANENT_PATTERN = ('gs://dartium-archive/drt-%(osname)s-%(bot)s/drt-'
|
||||
'%(osname)s-%(bot)s-%(num1)s.%(num2)s.zip')
|
||||
|
||||
DARTIUM_DIR = os.path.join('client', 'tests', 'dartium')
|
||||
DARTIUM_VERSION = os.path.join(DARTIUM_DIR, 'LAST_VERSION')
|
||||
DARTIUM_LATEST_PATTERN = (
|
||||
'gs://dartium-archive/latest/dartium-%(osname)s-%(bot)s-*.zip')
|
||||
DARTIUM_PERMANENT_PATTERN = ('gs://dartium-archive/dartium-%(osname)s-%(bot)s/'
|
||||
'dartium-%(osname)s-%(bot)s-%(num1)s.%(num2)s.zip')
|
||||
|
||||
SDK_DIR = os.path.join(utils.GetBuildRoot(utils.GuessOS(), 'release', 'ia32'),
|
||||
'dart-sdk')
|
||||
SDK_VERSION = os.path.join(SDK_DIR, 'LAST_VERSION')
|
||||
SDK_LATEST_PATTERN = 'gs://dart-archive/channels/dev/raw/latest/VERSION'
|
||||
# TODO(efortuna): Once the x64 VM also is optimized, select the version
|
||||
# based on whether we are running on a 32-bit or 64-bit system.
|
||||
SDK_PERMANENT = ('gs://dart-archive/channels/dev/raw/%(version_num)s/sdk/' +
|
||||
'dartsdk-%(osname)s-ia32-release.zip')
|
||||
|
||||
# Dictionary storing the earliest revision of each download we have stored.
|
||||
LAST_VALID = {'dartium': 4285, 'chromedriver': 7823, 'sdk': 9761, 'drt': 5342}
|
||||
|
||||
sys.path.append(os.path.join(GSUTIL_DIR, 'third_party', 'boto'))
|
||||
import boto
|
||||
|
||||
|
||||
def ExecuteCommand(*cmd):
|
||||
"""Execute a command in a subprocess."""
|
||||
pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
output, error = pipe.communicate()
|
||||
return pipe.returncode, output
|
||||
|
||||
|
||||
def ExecuteCommandVisible(*cmd):
|
||||
"""Execute a command in a subprocess, but show stdout/stderr."""
|
||||
result = subprocess.call(cmd, stdout=sys.stdout, stderr=sys.stderr,
|
||||
stdin=sys.stdin)
|
||||
if result != 0:
|
||||
raise Exception('Execution of "%s" failed' % ' '.join(cmd))
|
||||
|
||||
|
||||
def Gsutil(*cmd):
|
||||
return ExecuteCommand('python', GSUTIL, *cmd)
|
||||
|
||||
|
||||
def GsutilVisible(*cmd):
|
||||
ExecuteCommandVisible('python', GSUTIL, *cmd)
|
||||
|
||||
|
||||
def HasBotoConfig():
|
||||
"""Returns true if boto config exists."""
|
||||
|
||||
config_paths = boto.pyami.config.BotoConfigLocations
|
||||
if 'AWS_CREDENTIAL_FILE' in os.environ:
|
||||
config_paths.append(os.environ['AWS_CREDENTIAL_FILE'])
|
||||
for config_path in config_paths:
|
||||
if os.path.exists(config_path):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def InRunhooks():
|
||||
"""True if this script was called by "gclient runhooks" or "gclient sync\""""
|
||||
return 'runhooks' in sys.argv
|
||||
|
||||
|
||||
def GetDartiumRevision(name, bot, directory, version_file, latest_pattern,
|
||||
permanent_prefix, revision_num=None):
|
||||
"""Get the latest binary that is stored in the dartium archive.
|
||||
|
||||
Args:
|
||||
name: the name of the desired download.
|
||||
directory: target directory (recreated) to install binary
|
||||
version_file: name of file with the current version stamp
|
||||
latest_pattern: the google store url pattern pointing to the latest binary
|
||||
permanent_prefix: stable google store folder used to download versions
|
||||
revision_num: The desired revision number to retrieve. If revision_num is
|
||||
None, we return the latest revision. If the revision number is specified
|
||||
but unavailable, find the nearest older revision and use that instead.
|
||||
"""
|
||||
osdict = {'Darwin':'mac-x64', 'Linux':'linux-x64', 'Windows':'win-ia32'}
|
||||
|
||||
def FindPermanentUrl(out, osname, the_revision_num):
|
||||
output_lines = out.split()
|
||||
latest = output_lines[-1]
|
||||
if not the_revision_num:
|
||||
latest = (permanent_prefix[:permanent_prefix.rindex('/')] % { 'osname' :
|
||||
osname, 'bot' : bot } + latest[latest.rindex('/'):])
|
||||
else:
|
||||
latest = (permanent_prefix % { 'osname' : osname, 'num1' : the_revision_num,
|
||||
'num2' : the_revision_num, 'bot' : bot })
|
||||
foundURL = False
|
||||
while not foundURL:
|
||||
# Test to ensure this URL exists because the dartium-archive builds can
|
||||
# have unusual numbering (a range of CL numbers) sometimes.
|
||||
result, out = Gsutil('ls', permanent_prefix % {'osname' : osname,
|
||||
'num1': the_revision_num, 'num2': '*', 'bot': bot })
|
||||
if result == 0:
|
||||
# First try to find one with the second number the same as the
|
||||
# requested number.
|
||||
latest = out.split()[0]
|
||||
# Now test that the permissions are correct so you can actually
|
||||
# download it.
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
temp_zip = os.path.join(temp_dir, 'foo.zip')
|
||||
returncode, out = Gsutil('cp', latest, 'file://' + temp_zip)
|
||||
if returncode == 0:
|
||||
foundURL = True
|
||||
else:
|
||||
# Unable to download this item (most likely because something went
|
||||
# wrong on the upload and the permissions are bad). Keep looking for
|
||||
# a different URL.
|
||||
the_revision_num = int(the_revision_num) - 1
|
||||
shutil.rmtree(temp_dir)
|
||||
else:
|
||||
# Now try to find one with a nearby CL num.
|
||||
the_revision_num = int(the_revision_num) - 1
|
||||
if the_revision_num <= 0:
|
||||
TooEarlyError()
|
||||
return latest
|
||||
|
||||
GetFromGsutil(name, directory, version_file, latest_pattern, osdict,
|
||||
FindPermanentUrl, revision_num, bot)
|
||||
|
||||
|
||||
def GetSdkRevision(name, directory, version_file, latest_pattern,
|
||||
permanent_prefix, revision_num):
|
||||
"""Get a revision of the SDK from the editor build archive.
|
||||
|
||||
Args:
|
||||
name: the name of the desired download
|
||||
directory: target directory (recreated) to install binary
|
||||
version_file: name of file with the current version stamp
|
||||
latest_pattern: the google store url pattern pointing to the latest binary
|
||||
permanent_prefix: stable google store folder used to download versions
|
||||
revision_num: the desired revision number, or None for the most recent
|
||||
"""
|
||||
osdict = {'Darwin':'macos', 'Linux':'linux', 'Windows':'win32'}
|
||||
def FindPermanentUrl(out, osname, not_used):
|
||||
rev_num = revision_num
|
||||
if not rev_num:
|
||||
temp_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
temp_file.close()
|
||||
temp_file_url = 'file://' + temp_file.name
|
||||
Gsutil('cp', latest_pattern % {'osname' : osname }, temp_file_url)
|
||||
temp_file = open(temp_file.name)
|
||||
temp_file.seek(0)
|
||||
version_info = temp_file.read()
|
||||
temp_file.close()
|
||||
os.unlink(temp_file.name)
|
||||
if version_info != '':
|
||||
rev_num = json.loads(version_info)['revision']
|
||||
else:
|
||||
print 'Unable to get latest version information.'
|
||||
return ''
|
||||
latest = (permanent_prefix % { 'osname' : osname, 'version_num': rev_num})
|
||||
return latest
|
||||
|
||||
GetFromGsutil(name, directory, version_file, latest_pattern, osdict,
|
||||
FindPermanentUrl, revision_num)
|
||||
|
||||
|
||||
def GetFromGsutil(name, directory, version_file, latest_pattern,
|
||||
os_name_dict, get_permanent_url, revision_num = '', bot = None):
|
||||
"""Download and unzip the desired file from Google Storage.
|
||||
Args:
|
||||
name: the name of the desired download
|
||||
directory: target directory (recreated) to install binary
|
||||
version_file: name of file with the current version stamp
|
||||
latest_pattern: the google store url pattern pointing to the latest binary
|
||||
os_name_dict: a dictionary of operating system names and their corresponding
|
||||
strings on the google storage site.
|
||||
get_permanent_url: a function that accepts a listing of available files
|
||||
and the os name, and returns a permanent URL for downloading.
|
||||
revision_num: the desired revision number to get (if not supplied, we get
|
||||
the latest revision)
|
||||
"""
|
||||
system = platform.system()
|
||||
try:
|
||||
osname = os_name_dict[system]
|
||||
except KeyError:
|
||||
print >>sys.stderr, ('WARNING: platform "%s" does not support'
|
||||
'%s.') % (system, name)
|
||||
return 0
|
||||
|
||||
# Query for the latest version
|
||||
pattern = latest_pattern % { 'osname' : osname, 'bot' : bot }
|
||||
result, out = Gsutil('ls', pattern)
|
||||
if result == 0:
|
||||
# use permanent link instead, just in case the latest zip entry gets deleted
|
||||
# while we are downloading it.
|
||||
latest = get_permanent_url(out, osname, revision_num)
|
||||
else: # e.g. no access
|
||||
print "Couldn't download %s: %s\n%s" % (name, pattern, out)
|
||||
if not os.path.exists(version_file):
|
||||
print "Using %s will not work. Please try again later." % name
|
||||
return 0
|
||||
|
||||
# Check if we need to update the file
|
||||
if os.path.exists(version_file):
|
||||
v = open(version_file, 'r').read()
|
||||
if v == latest:
|
||||
if not InRunhooks():
|
||||
print name + ' is up to date.\nVersion: ' + latest
|
||||
return 0 # up to date
|
||||
|
||||
# download the zip file to a temporary path, and unzip to the target location
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
try:
|
||||
temp_zip = os.path.join(temp_dir, 'drt.zip')
|
||||
temp_zip_url = 'file://' + temp_zip
|
||||
# It's nice to show download progress
|
||||
GsutilVisible('cp', latest, temp_zip_url)
|
||||
|
||||
if platform.system() != 'Windows':
|
||||
# The Python zip utility does not preserve executable permissions, but
|
||||
# this does not seem to be a problem for Windows, which does not have a
|
||||
# built in zip utility. :-/
|
||||
result, out = ExecuteCommand('unzip', temp_zip, '-d', temp_dir)
|
||||
if result != 0:
|
||||
raise Exception('Execution of "unzip %s -d %s" failed: %s' %
|
||||
(temp_zip, temp_dir, str(out)))
|
||||
unzipped_dir = temp_dir + '/' + os.path.basename(latest)[:-len('.zip')]
|
||||
else:
|
||||
z = zipfile.ZipFile(temp_zip)
|
||||
z.extractall(temp_dir)
|
||||
unzipped_dir = os.path.join(temp_dir,
|
||||
os.path.basename(latest)[:-len('.zip')])
|
||||
z.close()
|
||||
if directory == SDK_DIR:
|
||||
unzipped_dir = os.path.join(temp_dir, 'dart-sdk')
|
||||
if os.path.exists(directory):
|
||||
print 'Removing old %s tree %s' % (name, directory)
|
||||
shutil.rmtree(directory)
|
||||
if os.path.exists(directory):
|
||||
raise Exception(
|
||||
'Removal of directory %s failed. Is the executable running?' %
|
||||
directory)
|
||||
shutil.move(unzipped_dir, directory)
|
||||
finally:
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
# create the version stamp
|
||||
v = open(version_file, 'w')
|
||||
v.write(latest)
|
||||
v.close()
|
||||
|
||||
print 'Successfully downloaded to %s' % directory
|
||||
return 0
|
||||
|
||||
|
||||
def TooEarlyError():
|
||||
"""Quick shortcutting function, to return early if someone requests a revision
|
||||
that is smaller than the earliest stored. This saves us from doing repeated
|
||||
requests until we get down to 0."""
|
||||
print ('Unable to download requested revision because it is earlier than the '
|
||||
'earliest revision stored.')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def CopyDrtFont(drt_dir):
|
||||
if platform.system() != 'Windows':
|
||||
return
|
||||
shutil.copy('third_party/drt_resources/AHEM____.TTF', drt_dir)
|
||||
|
||||
|
||||
def main():
|
||||
parser = optparse.OptionParser(usage='usage: %prog [options] download_name')
|
||||
parser.add_option('-r', '--revision', dest='revision',
|
||||
help='Desired revision number to retrieve for the SDK. If '
|
||||
'unspecified, retrieve the latest SDK build.',
|
||||
action='store', default=None)
|
||||
parser.add_option('-d', '--debug', dest='debug',
|
||||
help='Download a debug archive instead of a release.',
|
||||
action='store_true', default=False)
|
||||
args, positional = parser.parse_args()
|
||||
|
||||
if args.revision and int(args.revision) < LAST_VALID[positional[0]]:
|
||||
return TooEarlyError()
|
||||
|
||||
# Use the incremental release bot ('dartium-*-inc-be') by default.
|
||||
# Issue 13399 Quick fix, update with channel support.
|
||||
bot = 'inc-be'
|
||||
if args.debug:
|
||||
print >>sys.stderr, (
|
||||
'Debug versions of Dartium and content_shell not available')
|
||||
return 1
|
||||
|
||||
if positional[0] == 'dartium':
|
||||
GetDartiumRevision('Dartium', bot, DARTIUM_DIR, DARTIUM_VERSION,
|
||||
DARTIUM_LATEST_PATTERN, DARTIUM_PERMANENT_PATTERN,
|
||||
args.revision)
|
||||
elif positional[0] == 'sdk':
|
||||
GetSdkRevision('sdk', SDK_DIR, SDK_VERSION, SDK_LATEST_PATTERN,
|
||||
SDK_PERMANENT, args.revision)
|
||||
elif positional[0] == 'drt':
|
||||
GetDartiumRevision('content_shell', bot, DRT_DIR, DRT_VERSION,
|
||||
DRT_LATEST_PATTERN, DRT_PERMANENT_PATTERN,
|
||||
args.revision)
|
||||
CopyDrtFont(DRT_DIR)
|
||||
else:
|
||||
print ('Please specify the target you wish to download from Google Storage '
|
||||
'("drt", "dartium", "chromedriver", or "sdk")')
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
|
@ -25,7 +25,6 @@ POSIX_INFO = 'ps -p %s -o args'
|
|||
EXECUTABLE_NAMES = {
|
||||
'win32': {
|
||||
'chrome': 'chrome.exe',
|
||||
'content_shell': 'content_shell.exe',
|
||||
'dart_bootstrap': 'dart_bootstrap.exe',
|
||||
'dart': 'dart.exe',
|
||||
'dart_precompiled_runtime': 'dart_precompiled_runtime.exe',
|
||||
|
@ -38,7 +37,6 @@ EXECUTABLE_NAMES = {
|
|||
},
|
||||
'linux': {
|
||||
'chrome': 'chrome',
|
||||
'content_shell': 'content_shell',
|
||||
'dart_bootstrap': 'dart_bootstrap',
|
||||
'dart': 'dart',
|
||||
'dart_precompiled_runtime': 'dart_precompiled_runtime',
|
||||
|
@ -49,7 +47,6 @@ EXECUTABLE_NAMES = {
|
|||
'macos': {
|
||||
'chrome': 'Chrome',
|
||||
'chrome_helper': 'Chrome Helper',
|
||||
'content_shell': 'Content Shell',
|
||||
'dart_bootstrap': 'dart_bootstrap',
|
||||
'dart': 'dart',
|
||||
'dart_precompiled_runtime': 'dart_precompiled_runtime',
|
||||
|
@ -221,12 +218,6 @@ def KillBrowsers():
|
|||
status += Kill('chrome_helper')
|
||||
status += Kill('iexplore')
|
||||
status += Kill('safari')
|
||||
if os_name == "win32":
|
||||
# TODO(29599): Let content_shell affect exit code on windows,
|
||||
# once issue with zombie renderers is fixed.
|
||||
Kill('content_shell')
|
||||
else:
|
||||
status += Kill('content_shell')
|
||||
return status
|
||||
|
||||
def KillVCSystems():
|
||||
|
|
|
@ -565,71 +565,6 @@ class IE extends Browser {
|
|||
String toString() => "IE";
|
||||
}
|
||||
|
||||
class AndroidBrowserConfig {
|
||||
final String name;
|
||||
final String package;
|
||||
final String activity;
|
||||
final String action;
|
||||
AndroidBrowserConfig(this.name, this.package, this.activity, this.action);
|
||||
}
|
||||
|
||||
final contentShellOnAndroidConfig = new AndroidBrowserConfig(
|
||||
'ContentShellOnAndroid',
|
||||
'org.chromium.content_shell_apk',
|
||||
'.ContentShellActivity',
|
||||
'android.intent.action.VIEW');
|
||||
|
||||
class AndroidBrowser extends Browser {
|
||||
final bool checkedMode;
|
||||
AdbDevice _adbDevice;
|
||||
AndroidBrowserConfig _config;
|
||||
|
||||
AndroidBrowser(
|
||||
this._adbDevice, this._config, this.checkedMode, String apkPath) {
|
||||
_binary = apkPath;
|
||||
}
|
||||
|
||||
Future<bool> start(String url) {
|
||||
var intent =
|
||||
new Intent(_config.action, _config.package, _config.activity, url);
|
||||
return _adbDevice.waitForBootCompleted().then((_) {
|
||||
return _adbDevice.forceStop(_config.package);
|
||||
}).then((_) {
|
||||
return _adbDevice.killAll();
|
||||
}).then((_) {
|
||||
return _adbDevice.adbRoot();
|
||||
}).then((_) {
|
||||
return _adbDevice.setProp("DART_FORWARDING_PRINT", "1");
|
||||
}).then((_) {
|
||||
if (checkedMode) {
|
||||
return _adbDevice.setProp("DART_FLAGS", "--checked");
|
||||
} else {
|
||||
return _adbDevice.setProp("DART_FLAGS", "");
|
||||
}
|
||||
}).then((_) {
|
||||
return _adbDevice.installApk(new Path(_binary));
|
||||
}).then((_) {
|
||||
return _adbDevice.startActivity(intent).then((_) => true);
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> close() {
|
||||
if (_adbDevice != null) {
|
||||
return _adbDevice.forceStop(_config.package).then((_) {
|
||||
return _adbDevice.killAll().then((_) => true);
|
||||
});
|
||||
}
|
||||
return new Future.value(true);
|
||||
}
|
||||
|
||||
void logBrowserInfoToTestBrowserOutput() {
|
||||
_testBrowserOutput.stdout
|
||||
.write('Android device id: ${_adbDevice.deviceId}\n');
|
||||
}
|
||||
|
||||
String toString() => _config.name;
|
||||
}
|
||||
|
||||
class AndroidChrome extends Browser {
|
||||
static const String viewAction = 'android.intent.action.VIEW';
|
||||
static const String mainAction = 'android.intent.action.MAIN';
|
||||
|
|
|
@ -16,16 +16,6 @@ import 'utils.dart';
|
|||
|
||||
/// A command executed as a step in a test case.
|
||||
class Command {
|
||||
static Command contentShell(
|
||||
String executable,
|
||||
String htmlFile,
|
||||
List<String> options,
|
||||
List<String> dartFlags,
|
||||
Map<String, String> environment) {
|
||||
return new ContentShellCommand._(
|
||||
executable, htmlFile, options, dartFlags, environment);
|
||||
}
|
||||
|
||||
static Command browserTest(String url, TestConfiguration configuration,
|
||||
{bool retry}) {
|
||||
return new BrowserTestCommand._(url, configuration, retry);
|
||||
|
@ -403,46 +393,6 @@ class AddFlagsKey {
|
|||
int get hashCode => flags.hashCode ^ env.hashCode;
|
||||
}
|
||||
|
||||
class ContentShellCommand extends ProcessCommand {
|
||||
ContentShellCommand._(
|
||||
String executable,
|
||||
String htmlFile,
|
||||
List<String> options,
|
||||
List<String> dartFlags,
|
||||
Map<String, String> environmentOverrides)
|
||||
: super._("content_shell", executable, _getArguments(options, htmlFile),
|
||||
_getEnvironment(environmentOverrides, dartFlags));
|
||||
|
||||
// Cache the modified environments in a map from the old environment and
|
||||
// the string of Dart flags to the new environment. Avoid creating new
|
||||
// environment object for each command object.
|
||||
static Map<AddFlagsKey, Map<String, String>> environments = {};
|
||||
|
||||
static Map<String, String> _getEnvironment(
|
||||
Map<String, String> env, List<String> dartFlags) {
|
||||
var needDartFlags = dartFlags != null && dartFlags.isNotEmpty;
|
||||
if (needDartFlags) {
|
||||
if (env == null) {
|
||||
env = const <String, String>{};
|
||||
}
|
||||
var flags = dartFlags.join(' ');
|
||||
return environments.putIfAbsent(
|
||||
new AddFlagsKey(flags, env),
|
||||
() => new Map<String, String>.from(env)
|
||||
..addAll({'DART_FLAGS': flags, 'DART_FORWARDING_PRINT': '1'}));
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
static List<String> _getArguments(List<String> options, String htmlFile) {
|
||||
var arguments = options.toList();
|
||||
arguments.add(htmlFile);
|
||||
return arguments;
|
||||
}
|
||||
|
||||
int get maxNumRetries => 3;
|
||||
}
|
||||
|
||||
class BrowserTestCommand extends Command {
|
||||
Runtime get browser => configuration.runtime;
|
||||
final String url;
|
||||
|
|
|
@ -129,180 +129,6 @@ class CommandOutput extends UniqueObject {
|
|||
}
|
||||
}
|
||||
|
||||
class ContentShellCommandOutput extends CommandOutput {
|
||||
// Although tests are reported as passing, content shell sometimes exits with
|
||||
// a nonzero exitcode which makes our builders extremely flaky.
|
||||
// See: http://dartbug.com/15139.
|
||||
// TODO(rnystrom): Is this still needed? The underlying bug is closed.
|
||||
static const _whitelistedContentShellExitCode = -1073740022;
|
||||
|
||||
static bool _failedBecauseOfFlakyInfrastructure(
|
||||
Command command, bool timedOut, List<int> stderrBytes) {
|
||||
// If the browser test failed, it may have been because content shell
|
||||
// and the virtual framebuffer X server didn't hook up, or it crashed with
|
||||
// a core dump. Sometimes content shell crashes after it has set the stdout
|
||||
// to PASS, so we have to do this check first.
|
||||
// Content shell also fails with a broken pipe message: Issue 26739
|
||||
var zygoteCrash =
|
||||
new RegExp(r"ERROR:zygote_linux\.cc\(\d+\)] write: Broken pipe");
|
||||
var stderr = decodeUtf8(stderrBytes);
|
||||
// TODO(7564): See http://dartbug.com/7564
|
||||
// This may not be happening anymore. Test by removing this suppression.
|
||||
if (stderr.contains(cannotOpenDisplayMessage) ||
|
||||
stderr.contains(failedToRunCommandMessage)) {
|
||||
DebugLogger.warning(
|
||||
"Warning: Failure because of missing XDisplay. Test ignored");
|
||||
return true;
|
||||
}
|
||||
// TODO(26739): See http://dartbug.com/26739
|
||||
if (zygoteCrash.hasMatch(stderr)) {
|
||||
DebugLogger.warning("Warning: Failure because of content_shell "
|
||||
"zygote crash. Test ignored");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
final bool _infraFailure;
|
||||
|
||||
ContentShellCommandOutput(
|
||||
Command command,
|
||||
int exitCode,
|
||||
bool timedOut,
|
||||
List<int> stdout,
|
||||
List<int> stderr,
|
||||
Duration time,
|
||||
bool compilationSkipped)
|
||||
: _infraFailure =
|
||||
_failedBecauseOfFlakyInfrastructure(command, timedOut, stderr),
|
||||
super(command, exitCode, timedOut, stdout, stderr, time,
|
||||
compilationSkipped, 0);
|
||||
|
||||
Expectation result(TestCase testCase) {
|
||||
if (_infraFailure) {
|
||||
return Expectation.ignore;
|
||||
}
|
||||
|
||||
// Handle crashes and timeouts first
|
||||
if (hasCrashed) return Expectation.crash;
|
||||
if (hasTimedOut) return Expectation.timeout;
|
||||
if (hasNonUtf8) return Expectation.nonUtf8Error;
|
||||
|
||||
var outcome = _getOutcome();
|
||||
|
||||
if (testCase.hasRuntimeError) {
|
||||
if (!outcome.canBeOutcomeOf(Expectation.runtimeError)) {
|
||||
return Expectation.missingRuntimeError;
|
||||
}
|
||||
}
|
||||
if (testCase.isNegative) {
|
||||
if (outcome.canBeOutcomeOf(Expectation.fail)) return Expectation.pass;
|
||||
return Expectation.fail;
|
||||
}
|
||||
return outcome;
|
||||
}
|
||||
|
||||
bool get successful => canRunDependendCommands;
|
||||
|
||||
bool get canRunDependendCommands {
|
||||
// We cannot rely on the exit code of content_shell as a method to
|
||||
// determine if we were successful or not.
|
||||
return super.canRunDependendCommands && !_didFail(null);
|
||||
}
|
||||
|
||||
bool get hasCrashed => super.hasCrashed || _rendererCrashed;
|
||||
|
||||
Expectation _getOutcome() {
|
||||
if (_browserTestFailure) {
|
||||
return Expectation.runtimeError;
|
||||
}
|
||||
return Expectation.pass;
|
||||
}
|
||||
|
||||
bool get _rendererCrashed =>
|
||||
decodeUtf8(super.stdout).contains("#CRASHED - rendere");
|
||||
|
||||
bool get _browserTestFailure {
|
||||
// Browser tests fail unless stdout contains
|
||||
// 'Content-Type: text/plain' followed by 'PASS'.
|
||||
var hasContentType = false;
|
||||
var stdoutLines = decodeUtf8(super.stdout).split("\n");
|
||||
var containsFail = false;
|
||||
var containsPass = false;
|
||||
for (String line in stdoutLines) {
|
||||
switch (line) {
|
||||
case 'Content-Type: text/plain':
|
||||
hasContentType = true;
|
||||
break;
|
||||
case 'FAIL':
|
||||
if (hasContentType) {
|
||||
containsFail = true;
|
||||
}
|
||||
break;
|
||||
case 'PASS':
|
||||
if (hasContentType) {
|
||||
containsPass = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasContentType) {
|
||||
if (containsFail && containsPass) {
|
||||
DebugLogger.warning("Test had 'FAIL' and 'PASS' in stdout. ($command)");
|
||||
}
|
||||
if (!containsFail && !containsPass) {
|
||||
DebugLogger.warning("Test had neither 'FAIL' nor 'PASS' in stdout. "
|
||||
"($command)");
|
||||
return true;
|
||||
}
|
||||
if (containsFail) {
|
||||
return true;
|
||||
}
|
||||
assert(containsPass);
|
||||
if (exitCode != 0) {
|
||||
var message = "All tests passed, but exitCode != 0. "
|
||||
"Actual exitcode: $exitCode. "
|
||||
"($command)";
|
||||
DebugLogger.warning(message);
|
||||
diagnostics.add(message);
|
||||
}
|
||||
|
||||
var isWindows = io.Platform.operatingSystem == 'windows';
|
||||
return (!hasCrashed &&
|
||||
exitCode != 0 &&
|
||||
(!isWindows || exitCode != _whitelistedContentShellExitCode));
|
||||
}
|
||||
|
||||
DebugLogger.warning("Couldn't find 'Content-Type: text/plain' in output. "
|
||||
"($command).");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class HtmlBrowserCommandOutput extends ContentShellCommandOutput {
|
||||
HtmlBrowserCommandOutput(
|
||||
Command command,
|
||||
int exitCode,
|
||||
bool timedOut,
|
||||
List<int> stdout,
|
||||
List<int> stderr,
|
||||
Duration time,
|
||||
bool compilationSkipped)
|
||||
: super(command, exitCode, timedOut, stdout, stderr, time,
|
||||
compilationSkipped);
|
||||
|
||||
bool _didFail(TestCase testCase) {
|
||||
return _getOutcome() != Expectation.pass;
|
||||
}
|
||||
|
||||
bool get _browserTestFailure {
|
||||
// We should not need to convert back and forward.
|
||||
var output = decodeUtf8(super.stdout);
|
||||
if (output.contains("FAIL")) return true;
|
||||
return !output.contains("PASS");
|
||||
}
|
||||
}
|
||||
|
||||
class BrowserTestJsonResult {
|
||||
static const _allowedTypes = const [
|
||||
'sync_exception',
|
||||
|
@ -976,13 +802,7 @@ class ScriptCommandOutput extends CommandOutput {
|
|||
CommandOutput createCommandOutput(Command command, int exitCode, bool timedOut,
|
||||
List<int> stdout, List<int> stderr, Duration time, bool compilationSkipped,
|
||||
[int pid = 0]) {
|
||||
if (command is ContentShellCommand) {
|
||||
return new ContentShellCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
|
||||
} else if (command is BrowserTestCommand) {
|
||||
return new HtmlBrowserCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
|
||||
} else if (command is AnalysisCommand) {
|
||||
if (command is AnalysisCommand) {
|
||||
return new AnalysisCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
|
||||
} else if (command is SpecParseCommand) {
|
||||
|
|
|
@ -113,18 +113,13 @@ flutter: Run Dart code on the Flutter engine.
|
|||
dart_precompiled: Run a precompiled snapshot on the VM without a JIT.
|
||||
d8: Run JavaScript from the command line using v8.
|
||||
jsshell: Run JavaScript from the command line using Firefox js-shell.
|
||||
drt: Run Dart or JavaScript in the headless version of Chrome,
|
||||
Content shell.
|
||||
|
||||
ContentShellOnAndroid: Run Dart or JavaScript in content shell on Android.
|
||||
|
||||
ff:
|
||||
firefox:
|
||||
chrome:
|
||||
safari:
|
||||
ie9:
|
||||
ie10:
|
||||
ie11:
|
||||
opera:
|
||||
chromeOnAndroid: Run JavaScript in the specified browser.
|
||||
|
||||
self_check: Pass each test or its compiled output to every file under
|
||||
|
@ -238,7 +233,6 @@ compact, color, line, verbose, silent, status, buildbot, diff''',
|
|||
new _Option.bool('time', 'Print timing information after running tests.'),
|
||||
new _Option('dart', 'Path to dart executable.', hide: true),
|
||||
new _Option('flutter', 'Path to flutter executable.', hide: true),
|
||||
new _Option('drt', 'Path to content shell executable.', hide: true),
|
||||
new _Option('firefox', 'Path to firefox browser executable.', hide: true),
|
||||
new _Option('chrome', 'Path to chrome browser executable.', hide: true),
|
||||
new _Option('safari', 'Path to safari browser executable.', hide: true),
|
||||
|
|
|
@ -200,25 +200,7 @@ class DartVmRuntimeConfiguration extends RuntimeConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
/// Runtime configuration for Content Shell. We previously used a similar
|
||||
/// program named Dump Render Tree, hence the name.
|
||||
class DrtRuntimeConfiguration extends DartVmRuntimeConfiguration {
|
||||
int timeoutMultiplier(
|
||||
{Mode mode,
|
||||
bool isChecked: false,
|
||||
bool isReload: false,
|
||||
Architecture arch}) {
|
||||
return 4 // Allow additional time for browser testing to run.
|
||||
// TODO(ahe): We might need to distinguish between DRT for running
|
||||
// JavaScript and Dart code. I'm not convinced the inherited timeout
|
||||
// multiplier is relevant for JavaScript.
|
||||
*
|
||||
super.timeoutMultiplier(
|
||||
mode: mode, isChecked: isChecked, isReload: isReload);
|
||||
}
|
||||
}
|
||||
|
||||
/// The standalone Dart VM binary, "dart" or "dart.exe".
|
||||
//// The standalone Dart VM binary, "dart" or "dart.exe".
|
||||
class StandaloneDartRuntimeConfiguration extends DartVmRuntimeConfiguration {
|
||||
List<Command> computeRuntimeCommands(
|
||||
TestSuite suite,
|
||||
|
|
|
@ -1360,14 +1360,6 @@ bool shouldRetryCommand(CommandOutput output) {
|
|||
}
|
||||
}
|
||||
|
||||
// As long as we use a legacy version of our custom content_shell (which
|
||||
// became quite flaky after chrome-50 roll) we'll re-run tests on it.
|
||||
// The plan is to use chrome's content_shell instead of our own.
|
||||
// See http://dartbug.com/29655 .
|
||||
if (command is ContentShellCommand) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (io.Platform.operatingSystem == 'linux') {
|
||||
decodeOutput();
|
||||
// No matter which command we ran: If we get failures due to the
|
||||
|
|
|
@ -1062,7 +1062,7 @@ class StandardTestSuite extends TestSuite {
|
|||
}
|
||||
|
||||
// Construct the command(s) that compile all the inputs needed by the
|
||||
// browser test. For running Dart in DRT, this will be noop commands.
|
||||
// browser test.
|
||||
var commands = <Command>[];
|
||||
|
||||
void addCompileCommand(String fileName, String toPath) {
|
||||
|
@ -1245,17 +1245,6 @@ class StandardTestSuite extends TestSuite {
|
|||
alwaysCompile: !useSdk);
|
||||
}
|
||||
|
||||
String get contentShellFilename {
|
||||
if (configuration.drtPath != null) return configuration.drtPath;
|
||||
|
||||
if (Platform.operatingSystem == 'macos') {
|
||||
final path = dartDir.append(
|
||||
'/client/tests/drt/Content Shell.app/Contents/MacOS/Content Shell');
|
||||
return path.toNativePath();
|
||||
}
|
||||
return dartDir.append('client/tests/drt/content_shell').toNativePath();
|
||||
}
|
||||
|
||||
List<String> commonArgumentsFromFile(
|
||||
Path filePath, Map<String, dynamic> optionsFromFile) {
|
||||
var args = configuration.standardOptions.toList();
|
||||
|
@ -1345,41 +1334,17 @@ class StandardTestSuite extends TestSuite {
|
|||
*
|
||||
* // OtherScripts=file1.dart file2.dart
|
||||
*
|
||||
* - You can indicate whether a test is treated as a web-only test by
|
||||
* using an explicit import to a part of the dart:html library:
|
||||
* - Most tests are not web tests, but can (and will be) wrapped within
|
||||
* an HTML file and another script file to test them also on browser
|
||||
* environments (e.g. language and corelib tests are run this way).
|
||||
* We deduce that if a file with the same name as the test, but ending in
|
||||
* .html instead of .dart exists, the test was intended to be a web test
|
||||
* and no wrapping is necessary.
|
||||
*
|
||||
* import 'dart:html';
|
||||
* import 'dart:web_audio';
|
||||
* import 'dart:indexed_db';
|
||||
* import 'dart:svg';
|
||||
* import 'dart:web_sql';
|
||||
*
|
||||
* Most tests are not web tests, but can (and will be) wrapped within
|
||||
* another script file to test them also on browser environments (e.g.
|
||||
* language and corelib tests are run this way). We deduce that if this
|
||||
* import is specified, the test was intended to be a web test and no
|
||||
* wrapping is necessary.
|
||||
*
|
||||
* - You can convert DRT web-tests into layout-web-tests by specifying a
|
||||
* test expectation file. An expectation file is located in the same
|
||||
* location as the test, it has the same file name, except for the extension
|
||||
* (which can be either .txt or .png).
|
||||
*
|
||||
* When there are no expectation files, 'test.dart' assumes tests fail if
|
||||
* the process return a non-zero exit code (in the case of web tests, we
|
||||
* - 'test.dart' assumes tests fail if
|
||||
* the process returns a non-zero exit code (in the case of web tests, we
|
||||
* check for PASS/FAIL indications in the test output).
|
||||
*
|
||||
* When there is an expectation file, tests are run differently: the test
|
||||
* code is run to the end of the event loop and 'test.dart' takes a snapshot
|
||||
* of what is rendered in the page at that moment. This snapshot is
|
||||
* represented either in text form, if the expectation ends in .txt, or as
|
||||
* an image, if the expectation ends in .png. 'test.dart' will compare the
|
||||
* snapshot to the expectation file. When tests fail, 'test.dart' saves the
|
||||
* new snapshot into a file so it can be visualized or copied over.
|
||||
* Expectations can be recorded for the first time by creating an empty file
|
||||
* with the right name (touch test_name_test.png), running the test, and
|
||||
* executing the copy command printed by the test script.
|
||||
*
|
||||
* This method is static as the map is cached and shared amongst
|
||||
* configurations, so it may not use [configuration].
|
||||
*/
|
||||
|
@ -1643,7 +1608,7 @@ class StandardTestSuite extends TestSuite {
|
|||
}
|
||||
}
|
||||
|
||||
/// Used for testing packages in on off settings, i.e., we pass in the actual
|
||||
/// Used for testing packages in one-off settings, i.e., we pass in the actual
|
||||
/// directory that we want to test.
|
||||
class PKGTestSuite extends StandardTestSuite {
|
||||
PKGTestSuite(TestConfiguration configuration, Path directoryPath)
|
||||
|
|
Loading…
Reference in a new issue