Run integration tests on luci, use cipd package for Chrome (#18180)
* try to run integration tests on luci
* adds extra logs to check if chrome is on lUCI
* use the cipd chrome package for integration tests in LUCI
* add driver version for chrome 83.(cipd package has 83 now)
* no headless mode didn't worked on the bots. try the other option
* On LUCI also use chrome driver as a cipd package
* change the directory name to fit the cpid package
* adding blacklist functionality
* remove logs added for troubleshooting. remove the check that blocks int-test runs on LUCI
* add more comments to blacklists
* also use CIPD package chrome for unit tests
* addressing reviewer comments
* run integration tests first, upon reviewer request
* fix bug. keep running integration tests after unit tests
* update the logs for LUCI
* fix todo comments
diff --git a/lib/web_ui/dev/browser_lock.yaml b/lib/web_ui/dev/browser_lock.yaml
index 535847d..f83847d 100644
--- a/lib/web_ui/dev/browser_lock.yaml
+++ b/lib/web_ui/dev/browser_lock.yaml
@@ -1,7 +1,9 @@
chrome:
# It seems Chrome can't always release from the same build for all operating
# systems, so we specify per-OS build number.
- Linux: 753189
+ # Note: 741412 binary is for Chrome Version 82. Driver for Chrome version 83
+ # is not working with chrome.binary option.
+ Linux: 741412
Mac: 735194
Win: 735105
firefox:
diff --git a/lib/web_ui/dev/chrome_installer.dart b/lib/web_ui/dev/chrome_installer.dart
index 48e10de..6f46c2a 100644
--- a/lib/web_ui/dev/chrome_installer.dart
+++ b/lib/web_ui/dev/chrome_installer.dart
@@ -22,19 +22,20 @@
static ChromeArgParser get instance => _singletonInstance;
String _version;
+ int _pinnedChromeBuildNumber;
ChromeArgParser._();
@override
void populateOptions(ArgParser argParser) {
final YamlMap browserLock = BrowserLock.instance.configuration;
- final int pinnedChromeVersion =
+ _pinnedChromeBuildNumber =
PlatformBinding.instance.getChromeBuild(browserLock);
argParser
..addOption(
'chrome-version',
- defaultsTo: '$pinnedChromeVersion',
+ defaultsTo: '$pinnedChromeBuildNumber',
help: 'The Chrome version to use while running tests. If the requested '
'version has not been installed, it will be downloaded and installed '
'automatically. A specific Chrome build version number, such as 695653, '
@@ -51,6 +52,8 @@
@override
String get version => _version;
+
+ String get pinnedChromeBuildNumber => _pinnedChromeBuildNumber.toString();
}
/// Returns the installation of Chrome, installing it if necessary.
@@ -177,11 +180,22 @@
}
Future<void> install() async {
- if (versionDir.existsSync()) {
+ if (versionDir.existsSync() && !isLuci) {
versionDir.deleteSync(recursive: true);
+ versionDir.createSync(recursive: true);
+ } else if (versionDir.existsSync() && isLuci) {
+ print('INFO: Chrome version directory in LUCI: '
+ '${versionDir.path}');
+ } else if(!versionDir.existsSync() && isLuci) {
+ // Chrome should have been deployed as a CIPD package on LUCI.
+ // Throw if it does not exists.
+ throw StateError('Failed to locate Chrome on LUCI on path:'
+ '${versionDir.path}');
+ } else {
+ // If the directory does not exists and felt is not running on LUCI.
+ versionDir.createSync(recursive: true);
}
- versionDir.createSync(recursive: true);
final String url = PlatformBinding.instance.getChromeDownloadUrl(version);
final StreamedResponse download = await client.send(Request(
'GET',
@@ -241,9 +255,32 @@
return chromeDriverVersion;
}
+/// Make sure LUCI bot has the pinned Chrome version and return the executable.
+///
+/// We are using CIPD packages in LUCI. The pinned chrome version from the
+/// `browser_lock.yaml` file will already be installed in the LUCI bot.
+/// Verify if Chrome is installed and use it for the integration tests.
+String preinstalledChromeExecutable() {
+ // Note that build number and major version is different for Chrome.
+ // For example for a build number `753189`, major version is 83.
+ final String buildNumber = ChromeArgParser.instance.pinnedChromeBuildNumber;
+ final ChromeInstaller chromeInstaller = ChromeInstaller(version: buildNumber);
+ if (chromeInstaller.isInstalled) {
+ print('INFO: Found chrome executable for LUCI: '
+ '${chromeInstaller.getInstallation().executable}');
+ return chromeInstaller.getInstallation().executable;
+ } else {
+ throw StateError(
+ 'Failed to locate pinned Chrome build: $buildNumber on LUCI.');
+ }
+}
+
Future<int> _querySystemChromeMajorVersion() async {
String chromeExecutable = '';
- if (io.Platform.isLinux) {
+ // LUCI uses the Chrome from CIPD packages.
+ if (isLuci) {
+ chromeExecutable = preinstalledChromeExecutable();
+ } else if (io.Platform.isLinux) {
chromeExecutable = 'google-chrome';
} else if (io.Platform.isMacOS) {
chromeExecutable = await _findChromeExecutableOnMac();
diff --git a/lib/web_ui/dev/integration_tests_manager.dart b/lib/web_ui/dev/integration_tests_manager.dart
index ec3595d..04e7da3 100644
--- a/lib/web_ui/dev/integration_tests_manager.dart
+++ b/lib/web_ui/dev/integration_tests_manager.dart
@@ -9,6 +9,7 @@
import 'chrome_installer.dart';
import 'environment.dart';
import 'exceptions.dart';
+import 'common.dart';
import 'utils.dart';
class IntegrationTestsManager {
@@ -20,7 +21,8 @@
/// It usually changes with each the browser version changes.
/// A better solution would be installing the browser and the driver at the
/// same time.
- // TODO(nurhan): https://github.com/flutter/flutter/issues/53179.
+ // TODO(nurhan): https://github.com/flutter/flutter/issues/53179. Partly
+ // solved. Remaining local integration tests using the locked Chrome version.
final io.Directory _browserDriverDir;
/// This is the parent directory for all drivers.
@@ -33,7 +35,10 @@
IntegrationTestsManager(this._browser, this._useSystemFlutter)
: this._browserDriverDir = io.Directory(pathlib.join(
- environment.webUiDartToolDir.path, 'drivers', _browser)),
+ environment.webUiDartToolDir.path,
+ 'drivers',
+ _browser,
+ '${_browser}driver-${io.Platform.operatingSystem.toString()}')),
this._drivers = io.Directory(
pathlib.join(environment.webUiDartToolDir.path, 'drivers'));
@@ -42,7 +47,13 @@
print('WARNING: integration tests are only supported on chrome for now');
return false;
} else {
- await prepareDriver();
+ if (!isLuci) {
+ // LUCI installs driver from CIPD, so we skip installing it on LUCI.
+ await _prepareDriver();
+ } else {
+ await _verifyDriverForLUCI();
+ }
+ await _startDriver(_browserDriverDir.path);
// TODO(nurhan): https://github.com/flutter/flutter/issues/52987
return await _runTests();
}
@@ -65,7 +76,7 @@
Future<void> _cloneFlutterRepo() async {
// Delete directory if exists.
if (environment.engineDartToolDir.existsSync()) {
- environment.engineDartToolDir.deleteSync();
+ environment.engineDartToolDir.deleteSync(recursive: true);
}
environment.engineDartToolDir.createSync();
@@ -88,13 +99,23 @@
useSystemFlutter: _useSystemFlutter);
}
- void _runDriver() async {
- startProcess('./chromedriver/chromedriver', ['--port=4444'],
- workingDirectory: io.Directory.current.path);
+ /// Driver should already exist on LUCI as a CIPD package.
+ ///
+ /// Throw an error if directory does not exists.
+ void _verifyDriverForLUCI() {
+ if (!_browserDriverDir.existsSync()) {
+ throw StateError('Failed to locate Chrome driver on LUCI on path:'
+ '${_browserDriverDir.path}');
+ }
+ }
+
+ void _startDriver(String workingDirectory) async {
+ await startProcess('./chromedriver/chromedriver', ['--port=4444'],
+ workingDirectory: workingDirectory);
print('INFO: Driver started');
}
- void prepareDriver() async {
+ void _prepareDriver() async {
if (_browserDriverDir.existsSync()) {
_browserDriverDir.deleteSync(recursive: true);
}
@@ -110,7 +131,6 @@
ChromeDriverInstaller chromeDriverInstaller =
ChromeDriverInstaller.withVersion(chromeDriverVersion);
await chromeDriverInstaller.install(alwaysInstall: true);
- await _runDriver();
io.Directory.current = temp;
}
@@ -153,6 +173,8 @@
.toList();
final List<String> e2eTestsToRun = List<String>();
+ final List<String> blackList =
+ blackListsMap[getBlackListMapKey(_browser)] ?? <String>[];
// The following loops over the contents of the directory and saves an
// expected driver file name for each e2e test assuming any dart file
@@ -162,7 +184,13 @@
for (io.File f in entities) {
final String basename = pathlib.basename(f.path);
if (!basename.contains('_test.dart') && basename.endsWith('.dart')) {
- e2eTestsToRun.add(basename);
+ // Do not add the basename if it is in the blacklist.
+ if (!blackList.contains(basename)) {
+ e2eTestsToRun.add(basename);
+ } else {
+ print('INFO: Test $basename is skipped since it is blacklisted for '
+ '${getBlackListMapKey(_browser)}');
+ }
}
}
@@ -200,15 +228,21 @@
'web-server',
'--profile',
'--browser-name=$_browser',
+ if (isLuci) '--chrome-binary=${preinstalledChromeExecutable()}',
+ if (isLuci) '--headless',
'--local-engine=host_debug_unopt',
],
workingDirectory: directory.path,
);
if (exitCode != 0) {
- final String statementToRun = 'flutter drive '
+ String statementToRun = 'flutter drive '
'--target=test_driver/${testName} -d web-server --profile '
'--browser-name=$_browser --local-engine=host_debug_unopt';
+ if (isLuci) {
+ statementToRun = '$statementToRun --chrome-binary='
+ '${preinstalledChromeExecutable()}';
+ }
io.stderr
.writeln('ERROR: Failed to run test. Exited with exit code $exitCode'
'. Statement to run $testName locally use the following '
@@ -321,3 +355,32 @@
}
}
}
+
+/// Prepares a key for the [blackList] map.
+///
+/// Uses the browser name and the operating system name.
+String getBlackListMapKey(String browser) =>
+ '${browser}-${io.Platform.operatingSystem}';
+
+/// Tests that should be skipped run for a specific platform-browser
+/// combination.
+///
+/// These tests might be failing or might have been implemented for a specific
+/// configuration.
+///
+/// For example a mobile browser only tests will be added to blacklist for
+/// `chrome-linux`, `safari-macos` and `chrome-macos`.
+///
+/// Note that integration tests are only running on chrome for now.
+const Map<String, List<String>> blackListsMap = <String, List<String>>{
+ 'chrome-linux': [
+ 'target_platform_ios_e2e.dart',
+ 'target_platform_macos_e2e.dart',
+ 'target_platform_android_e2e.dart',
+ ],
+ 'chrome-macos': [
+ 'target_platform_ios_e2e.dart',
+ 'target_platform_macos_e2e.dart',
+ 'target_platform_android_e2e.dart',
+ ],
+};
diff --git a/lib/web_ui/dev/test_runner.dart b/lib/web_ui/dev/test_runner.dart
index 30ffcfe..41f23d7 100644
--- a/lib/web_ui/dev/test_runner.dart
+++ b/lib/web_ui/dev/test_runner.dart
@@ -131,8 +131,8 @@
// TODO(nurhan): https://github.com/flutter/flutter/issues/53322
// TODO(nurhan): Expand browser matrix for felt integration tests.
if (runAllTests && isChrome) {
- bool integrationTestResult = await runIntegrationTests();
bool unitTestResult = await runUnitTests();
+ bool integrationTestResult = await runIntegrationTests();
if (integrationTestResult != unitTestResult) {
print('Tests run. Integration tests passed: $integrationTestResult '
'unit tests passed: $unitTestResult');
@@ -146,11 +146,6 @@
}
Future<bool> runIntegrationTests() async {
- // TODO(nurhan): https://github.com/flutter/flutter/issues/52983
- if (io.Platform.environment['LUCI_CONTEXT'] != null) {
- return true;
- }
-
return IntegrationTestsManager(browser, useSystemFlutter).runTests();
}