[web] use a different method for launching desktop safari (flutter/engine#27567)

This commit is contained in:
Yegor 2021-07-19 20:06:02 -06:00 committed by GitHub
parent b6dbaa079a
commit e2e4ee5df9
3 changed files with 39 additions and 98 deletions

View File

@ -1,63 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'utils.dart';
class MacOSInfo {
/// Print information collected from the operating system.
///
/// Built in tools such as `system_profiler` and `defaults` are utilized.
Future<void> printInformation() async {
await _printSafariApplications();
await _printSafariDefaults();
await _printUserLimits();
}
/// Print information on applications in the system that contains string
/// `Safari`.
Future<void> _printSafariApplications() async {
final ProcessManager systemProfiler = await startProcess(
'system_profiler',
<String>['SPApplicationsDataType', '-json'],
evalOutput: true,
);
final String systemProfileJson = await systemProfiler.evalStdout();
final Map<String, dynamic> json =
jsonDecode(systemProfileJson) as Map<String, dynamic>;
final List<dynamic> systemProfile = json.values.first as List<dynamic>;
for (int i = 0; i < systemProfile.length; i++) {
final Map<String, dynamic> application =
systemProfile[i] as Map<String, dynamic>;
final String applicationName = application['_name'] as String;
if (applicationName.contains('Safari')) {
print('application: $applicationName '
'fullInfo: ${application.toString()}');
}
}
}
/// Print all the defaults in the system related to Safari.
Future<void> _printSafariDefaults() async {
final ProcessManager defaults = await startProcess(
'/usr/bin/defaults',
<String>['find', 'Safari'],
evalOutput: true,
);
print('Safari related defaults:\n ${await defaults.evalStdout()}');
}
/// Print user limits (file and process).
Future<void> _printUserLimits() async {
ProcessManager ulimit = await startProcess('ulimit', <String>['-n'], evalOutput: true);
final String fileLimit = await ulimit.evalStdout();
print('MacOS file limit: $fileLimit');
ulimit = await startProcess('ulimit', <String>['-u'], evalOutput: true);
final String processLimit = await ulimit.evalStdout();
print('MacOS process limit: $processLimit');
}
}

View File

@ -3,13 +3,14 @@
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert' show json;
import 'dart:io';
import 'package:path/path.dart' as pathlib;
import 'package:test_api/src/backend/runtime.dart';
import 'browser.dart';
import 'common.dart';
import 'safari_installation.dart';
import 'utils.dart';
/// Provides an environment for the desktop variant of Safari running on macOS.
class SafariMacOsEnvironment implements BrowserEnvironment {
@ -45,34 +46,44 @@ class SafariMacOs extends Browser {
@override
final String name = 'Safari macOS';
/// Starts a new instance of Safari open to the given [url], which may be a
/// [Uri].
/// Starts a new instance of Safari open to the given [url].
factory SafariMacOs(Uri url) {
final String version = SafariArgParser.instance.version;
return SafariMacOs._(() async {
// TODO(nurhan): Configure info log for LUCI.
final BrowserInstallation installation = await getOrInstallSafari(
version,
infoLog: DevNull(),
);
// This hack to programmatically launch a test in Safari is borrowed from
// Karma: https://github.com/karma-runner/karma-safari-launcher/issues/29
//
// The issue is that opening an HTML file directly causes Safari to pop up
// a UI prompt to confirm the opening of a file. However, files under
// Library/Containers/com.apple.Safari/Data are exempt from this pop up.
// We create a "trampoline" file in this directory. The trampoline
// redirects the browser to the test URL in a <script>.
final String homePath = Platform.environment['HOME']!;
final Directory safariDataDirectory = Directory(pathlib.join(
homePath,
'Library/Containers/com.apple.Safari/Data',
));
final Directory trampolineDirectory = await safariDataDirectory.createTemp('web-engine-test-trampoline-');
// In the macOS Catalina opening Safari browser with a file brings
// a popup which halts the test.
// The following list of arguments needs to be provided to the `open`
// command to open Safari for a given URL. In summary, `open` tool opens
// a new Safari browser (even if one is already open), opens it with no
// persistent state and wait until it opens.
// The details copied from `man open` on macOS.
// TODO(nurhan): https://github.com/flutter/flutter/issues/50809
final Process process = await Process.start(installation.executable, <String>[
// These are flags for `open` command line tool.
'-F', // Open a fresh Safari with no persistent state.
'-W', // Wait until the Safari opens.
'-n', // Open a new instance of the Safari even another one is open.
'-b', // Specifies the bundle identifier for the application to use.
'com.apple.Safari', // Bundle identifier for Safari.
'${url.toString()}'
]);
// Clean up trampoline files/directories before exiting felt.
cleanupCallbacks.add(() async {
if (trampolineDirectory.existsSync()) {
trampolineDirectory.delete(recursive: true);
}
});
final File trampoline = File(
pathlib.join(trampolineDirectory.path, 'trampoline.html'),
);
await trampoline.writeAsString('''
<script>
location = ${json.encode(url.toString())};
</script>
''');
final Process process = await Process.start(
'/Applications/Safari.app/Contents/MacOS/Safari',
<String>[trampoline.path],
);
return process;
});

View File

@ -39,7 +39,6 @@ import 'environment.dart';
import 'exceptions.dart';
import 'firefox.dart';
import 'firefox_installer.dart';
import 'macos_info.dart';
import 'safari_installation.dart';
import 'safari_ios.dart';
import 'safari_macos.dart';
@ -180,14 +179,8 @@ class TestCommand extends Command<bool> with ArgUtils<bool> {
}
GeneralTestsArgumentParser.instance.parseOptions(argResults!);
/// Collect information on the bot.
if (isSafariOnMacOS && isLuci) {
final MacOSInfo macOsInfo = new MacOSInfo();
await macOsInfo.printInformation();
}
final Pipeline testPipeline = Pipeline(steps: <PipelineStep>[
ClearTerminalScreenStep(),
if (isWatchMode) ClearTerminalScreenStep(),
TestRunnerStep(this),
]);
await testPipeline.run();