Ian Hickson | 9ac1668 | 2017-06-12 16:52:35 -0700 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 5 | import 'dart:async'; |
Alexandre Ardhuin | 8c043d0 | 2017-02-23 22:37:26 +0100 | [diff] [blame] | 6 | import 'dart:io'; |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 7 | |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 8 | import 'package:googleapis/bigquery/v2.dart' as bq; |
| 9 | import 'package:googleapis_auth/auth_io.dart' as auth; |
| 10 | import 'package:http/http.dart' as http; |
Ian Hickson | aaa0a1c | 2017-04-13 10:22:41 -0700 | [diff] [blame] | 11 | import 'package:path/path.dart' as path; |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 12 | |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 13 | import 'flutter_compact_formatter.dart'; |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 14 | import 'run_command.dart'; |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 15 | |
Alexandre Ardhuin | d340e2f | 2018-10-04 18:44:23 +0200 | [diff] [blame] | 16 | typedef ShardRunner = Future<void> Function(); |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 17 | |
Ian Hickson | aaa0a1c | 2017-04-13 10:22:41 -0700 | [diff] [blame] | 18 | final String flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); |
| 19 | final String flutter = path.join(flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'); |
| 20 | final String dart = path.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', Platform.isWindows ? 'dart.exe' : 'dart'); |
| 21 | final String pub = path.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', Platform.isWindows ? 'pub.bat' : 'pub'); |
Greg Spencer | f29ecba | 2017-12-05 14:46:39 -0800 | [diff] [blame] | 22 | final String pubCache = path.join(flutterRoot, '.pub-cache'); |
Alexander Thomas | 425bd5a | 2017-12-09 00:49:29 +0100 | [diff] [blame] | 23 | final List<String> flutterTestArgs = <String>[]; |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 24 | |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 25 | |
| 26 | final bool useFlutterTestFormatter = Platform.environment['FLUTTER_TEST_FORMATTER'] == 'true'; |
| 27 | |
Jonah Williams | 55a2ee5 | 2019-03-18 15:50:11 -0700 | [diff] [blame] | 28 | final bool noUseBuildRunner = Platform.environment['FLUTTER_TEST_NO_BUILD_RUNNER'] == 'true'; |
| 29 | |
Alexandre Ardhuin | eda03e2 | 2018-08-02 12:02:32 +0200 | [diff] [blame] | 30 | const Map<String, ShardRunner> _kShards = <String, ShardRunner>{ |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 31 | 'tests': _runTests, |
Greg Spencer | 90a5f46 | 2018-07-20 10:21:34 -0700 | [diff] [blame] | 32 | 'tool_tests': _runToolTests, |
Dan Field | 72926bd | 2018-11-29 09:32:11 -0800 | [diff] [blame] | 33 | 'build_tests': _runBuildTests, |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 34 | 'coverage': _runCoverage, |
Dan Field | 2a644f3 | 2019-03-10 07:52:44 -0700 | [diff] [blame] | 35 | 'integration_tests': _runIntegrationTests, |
Dan Field | b484a91 | 2019-02-23 09:56:27 -0800 | [diff] [blame] | 36 | 'add2app_test': _runAdd2AppTest, |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 37 | }; |
| 38 | |
Alexandre Ardhuin | eda03e2 | 2018-08-02 12:02:32 +0200 | [diff] [blame] | 39 | const Duration _kLongTimeout = Duration(minutes: 45); |
| 40 | const Duration _kShortTimeout = Duration(minutes: 5); |
Todd Volkert | 58d3493 | 2018-04-17 10:00:06 -0700 | [diff] [blame] | 41 | |
Alexander Thomas | 425bd5a | 2017-12-09 00:49:29 +0100 | [diff] [blame] | 42 | /// When you call this, you can pass additional arguments to pass custom |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 43 | /// arguments to flutter test. For example, you might want to call this |
Alexander Thomas | 425bd5a | 2017-12-09 00:49:29 +0100 | [diff] [blame] | 44 | /// script with the parameter --local-engine=host_debug_unopt to |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 45 | /// use your own build of the engine. |
Ian Hickson | 11c2032 | 2017-03-20 16:16:34 -0700 | [diff] [blame] | 46 | /// |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 47 | /// To run the tool_tests part, run it with SHARD=tool_tests |
Ian Hickson | 11c2032 | 2017-03-20 16:16:34 -0700 | [diff] [blame] | 48 | /// |
| 49 | /// For example: |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 50 | /// SHARD=tool_tests bin/cache/dart-sdk/bin/dart dev/bots/test.dart |
Alexander Thomas | 425bd5a | 2017-12-09 00:49:29 +0100 | [diff] [blame] | 51 | /// bin/cache/dart-sdk/bin/dart dev/bots/test.dart --local-engine=host_debug_unopt |
Alexandre Ardhuin | d340e2f | 2018-10-04 18:44:23 +0200 | [diff] [blame] | 52 | Future<void> main(List<String> args) async { |
Alexander Thomas | 425bd5a | 2017-12-09 00:49:29 +0100 | [diff] [blame] | 53 | flutterTestArgs.addAll(args); |
| 54 | |
Ian Hickson | 18c60d3 | 2018-01-17 10:17:52 -0800 | [diff] [blame] | 55 | final String shard = Platform.environment['SHARD']; |
| 56 | if (shard != null) { |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 57 | if (!_kShards.containsKey(shard)) { |
| 58 | print('Invalid shard: $shard'); |
| 59 | print('The available shards are: ${_kShards.keys.join(", ")}'); |
| 60 | exit(1); |
| 61 | } |
Ian Hickson | a9c1399 | 2018-01-29 21:14:41 -0800 | [diff] [blame] | 62 | print('${bold}SHARD=$shard$reset'); |
Ian Hickson | 18c60d3 | 2018-01-17 10:17:52 -0800 | [diff] [blame] | 63 | await _kShards[shard](); |
| 64 | } else { |
| 65 | for (String currentShard in _kShards.keys) { |
| 66 | print('${bold}SHARD=$currentShard$reset'); |
| 67 | await _kShards[currentShard](); |
Ian Hickson | a9c1399 | 2018-01-29 21:14:41 -0800 | [diff] [blame] | 68 | print(''); |
Ian Hickson | 18c60d3 | 2018-01-17 10:17:52 -0800 | [diff] [blame] | 69 | } |
| 70 | } |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 71 | } |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 72 | |
Alexandre Ardhuin | d340e2f | 2018-10-04 18:44:23 +0200 | [diff] [blame] | 73 | Future<void> _runSmokeTests() async { |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 74 | // Verify that the tests actually return failure on failure and success on |
| 75 | // success. |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 76 | final String automatedTests = path.join(flutterRoot, 'dev', 'automated_tests'); |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 77 | // We run the "pass" and "fail" smoke tests first, and alone, because those |
| 78 | // are particularly critical and sensitive. If one of these fails, there's no |
| 79 | // point even trying the others. |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 80 | await _runFlutterTest(automatedTests, |
| 81 | script: path.join('test_smoke_test', 'pass_test.dart'), |
| 82 | printOutput: false, |
Todd Volkert | 58d3493 | 2018-04-17 10:00:06 -0700 | [diff] [blame] | 83 | timeout: _kShortTimeout, |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 84 | ); |
| 85 | await _runFlutterTest(automatedTests, |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 86 | script: path.join('test_smoke_test', 'fail_test.dart'), |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 87 | expectFailure: true, |
| 88 | printOutput: false, |
Todd Volkert | 58d3493 | 2018-04-17 10:00:06 -0700 | [diff] [blame] | 89 | timeout: _kShortTimeout, |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 90 | ); |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 91 | // We run the timeout tests individually because they are timing-sensitive. |
| 92 | await _runFlutterTest(automatedTests, |
| 93 | script: path.join('test_smoke_test', 'timeout_pass_test.dart'), |
| 94 | expectFailure: false, |
| 95 | printOutput: false, |
| 96 | timeout: _kShortTimeout, |
| 97 | ); |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 98 | await _runFlutterTest(automatedTests, |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 99 | script: path.join('test_smoke_test', 'timeout_fail_test.dart'), |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 100 | expectFailure: true, |
| 101 | printOutput: false, |
Todd Volkert | 58d3493 | 2018-04-17 10:00:06 -0700 | [diff] [blame] | 102 | timeout: _kShortTimeout, |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 103 | ); |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 104 | // We run the remaining smoketests in parallel, because they each take some |
| 105 | // time to run (e.g. compiling), so we don't want to run them in series, |
| 106 | // especially on 20-core machines... |
| 107 | await Future.wait<void>( |
| 108 | <Future<void>>[ |
| 109 | _runFlutterTest(automatedTests, |
| 110 | script: path.join('test_smoke_test', 'crash1_test.dart'), |
| 111 | expectFailure: true, |
| 112 | printOutput: false, |
| 113 | timeout: _kShortTimeout, |
| 114 | ), |
| 115 | _runFlutterTest(automatedTests, |
| 116 | script: path.join('test_smoke_test', 'crash2_test.dart'), |
| 117 | expectFailure: true, |
| 118 | printOutput: false, |
| 119 | timeout: _kShortTimeout, |
| 120 | ), |
| 121 | _runFlutterTest(automatedTests, |
| 122 | script: path.join('test_smoke_test', 'syntax_error_test.broken_dart'), |
| 123 | expectFailure: true, |
| 124 | printOutput: false, |
| 125 | timeout: _kShortTimeout, |
| 126 | ), |
| 127 | _runFlutterTest(automatedTests, |
| 128 | script: path.join('test_smoke_test', 'missing_import_test.broken_dart'), |
| 129 | expectFailure: true, |
| 130 | printOutput: false, |
| 131 | timeout: _kShortTimeout, |
| 132 | ), |
| 133 | _runFlutterTest(automatedTests, |
| 134 | script: path.join('test_smoke_test', 'disallow_error_reporter_modification_test.dart'), |
| 135 | expectFailure: true, |
| 136 | printOutput: false, |
| 137 | timeout: _kShortTimeout, |
| 138 | ), |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 139 | runCommand(flutter, |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 140 | <String>['drive', '--use-existing-app', '-t', path.join('test_driver', 'failure.dart')], |
| 141 | workingDirectory: path.join(flutterRoot, 'packages', 'flutter_driver'), |
Greg Spencer | f44f625 | 2018-07-23 15:41:31 -0700 | [diff] [blame] | 142 | expectNonZeroExit: true, |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 143 | printOutput: false, |
| 144 | timeout: _kShortTimeout, |
| 145 | ), |
| 146 | ], |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 147 | ); |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 148 | |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 149 | // Verify that we correctly generated the version file. |
| 150 | await _verifyVersion(path.join(flutterRoot, 'version')); |
Greg Spencer | 90a5f46 | 2018-07-20 10:21:34 -0700 | [diff] [blame] | 151 | } |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 152 | |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 153 | Future<bq.BigqueryApi> _getBigqueryApi() async { |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 154 | if (!useFlutterTestFormatter) { |
| 155 | return null; |
| 156 | } |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 157 | // TODO(dnfield): How will we do this on LUCI? |
| 158 | final String privateKey = Platform.environment['GCLOUD_SERVICE_ACCOUNT_KEY']; |
Dan Field | b9f013c | 2019-03-10 11:26:17 -0700 | [diff] [blame] | 159 | // If we're on Cirrus and a non-collaborator is doing this, we can't get the key. |
| 160 | if (privateKey == null || privateKey.isEmpty || privateKey.startsWith('ENCRYPTED[')) { |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 161 | return null; |
| 162 | } |
Dan Field | b9f013c | 2019-03-10 11:26:17 -0700 | [diff] [blame] | 163 | try { |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 164 | final auth.ServiceAccountCredentials accountCredentials = auth.ServiceAccountCredentials( |
Dan Field | b9f013c | 2019-03-10 11:26:17 -0700 | [diff] [blame] | 165 | 'flutter-ci-test-reporter@flutter-infra.iam.gserviceaccount.com', |
| 166 | auth.ClientId.serviceAccount('114390419920880060881.apps.googleusercontent.com'), |
| 167 | '-----BEGIN PRIVATE KEY-----\n$privateKey\n-----END PRIVATE KEY-----\n', |
| 168 | ); |
| 169 | final List<String> scopes = <String>[bq.BigqueryApi.BigqueryInsertdataScope]; |
| 170 | final http.Client client = await auth.clientViaServiceAccount(accountCredentials, scopes); |
| 171 | return bq.BigqueryApi(client); |
| 172 | } catch (e) { |
| 173 | print('Failed to get BigQuery API client.'); |
| 174 | print(e); |
| 175 | return null; |
| 176 | } |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 177 | } |
| 178 | |
Alexandre Ardhuin | d340e2f | 2018-10-04 18:44:23 +0200 | [diff] [blame] | 179 | Future<void> _runToolTests() async { |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 180 | final bq.BigqueryApi bigqueryApi = await _getBigqueryApi(); |
Greg Spencer | 90a5f46 | 2018-07-20 10:21:34 -0700 | [diff] [blame] | 181 | await _runSmokeTests(); |
| 182 | |
Jonah Williams | 0a2175f | 2019-03-27 15:24:08 -0700 | [diff] [blame] | 183 | // The flutter_tool will currently be snapshotted without asserts. We need |
| 184 | // to force it to be regenerated with them enabled. |
| 185 | if (!Platform.isWindows) { |
| 186 | File(path.join(flutterRoot, 'bin', 'cache', 'flutter_tools.snapshot')).deleteSync(); |
| 187 | File(path.join(flutterRoot, 'bin', 'cache', 'flutter_tools.stamp')).deleteSync(); |
| 188 | } |
Jonah Williams | 55a2ee5 | 2019-03-18 15:50:11 -0700 | [diff] [blame] | 189 | if (noUseBuildRunner) { |
| 190 | await _pubRunTest( |
| 191 | path.join(flutterRoot, 'packages', 'flutter_tools'), |
| 192 | tableData: bigqueryApi?.tabledata, |
Jonah Williams | 0a2175f | 2019-03-27 15:24:08 -0700 | [diff] [blame] | 193 | enableFlutterToolAsserts: !Platform.isWindows, |
Jonah Williams | 55a2ee5 | 2019-03-18 15:50:11 -0700 | [diff] [blame] | 194 | ); |
| 195 | } else { |
| 196 | await _buildRunnerTest( |
| 197 | path.join(flutterRoot, 'packages', 'flutter_tools'), |
| 198 | flutterRoot, |
| 199 | tableData: bigqueryApi?.tabledata, |
Jonah Williams | 0a2175f | 2019-03-27 15:24:08 -0700 | [diff] [blame] | 200 | enableFlutterToolAsserts: !Platform.isWindows, |
Jonah Williams | 55a2ee5 | 2019-03-18 15:50:11 -0700 | [diff] [blame] | 201 | ); |
| 202 | } |
Greg Spencer | 90a5f46 | 2018-07-20 10:21:34 -0700 | [diff] [blame] | 203 | |
| 204 | print('${bold}DONE: All tests successful.$reset'); |
| 205 | } |
| 206 | |
Dan Field | 72926bd | 2018-11-29 09:32:11 -0800 | [diff] [blame] | 207 | /// Verifies that AOT, APK, and IPA (if on macOS) builds of some |
| 208 | /// examples apps finish without crashing. It does not actually |
| 209 | /// launch the apps. That happens later in the devicelab. This is |
| 210 | /// just a smoke-test. In particular, this will verify we can build |
| 211 | /// when there are spaces in the path name for the Flutter SDK and |
| 212 | /// target app. |
| 213 | Future<void> _runBuildTests() async { |
| 214 | final List<String> paths = <String>[ |
| 215 | path.join('examples', 'hello_world'), |
| 216 | path.join('examples', 'flutter_gallery'), |
| 217 | path.join('examples', 'flutter_view'), |
| 218 | ]; |
| 219 | for (String path in paths) { |
| 220 | await _flutterBuildAot(path); |
| 221 | await _flutterBuildApk(path); |
| 222 | await _flutterBuildIpa(path); |
| 223 | } |
Jonah Williams | 44b22c7 | 2019-03-25 18:47:37 -0700 | [diff] [blame] | 224 | await _flutterBuildDart2js(path.join('dev', 'integration_tests', 'web')); |
Yegor | 8d64301 | 2018-10-08 12:38:46 -0700 | [diff] [blame] | 225 | |
Dan Field | 72926bd | 2018-11-29 09:32:11 -0800 | [diff] [blame] | 226 | print('${bold}DONE: All build tests successful.$reset'); |
Yegor | 8d64301 | 2018-10-08 12:38:46 -0700 | [diff] [blame] | 227 | } |
| 228 | |
Jonah Williams | 44b22c7 | 2019-03-25 18:47:37 -0700 | [diff] [blame] | 229 | Future<void> _flutterBuildDart2js(String relativePathToApplication) async { |
| 230 | print('Running Dart2JS build tests...'); |
| 231 | await runCommand(flutter, |
| 232 | <String>['build', 'web', '-v'], |
| 233 | workingDirectory: path.join(flutterRoot, relativePathToApplication), |
| 234 | expectNonZeroExit: false, |
| 235 | timeout: _kShortTimeout, |
| 236 | ); |
| 237 | print('Done.'); |
| 238 | } |
Jonah Williams | 9bc5656 | 2019-02-14 22:42:30 -0800 | [diff] [blame] | 239 | |
Dan Field | 72926bd | 2018-11-29 09:32:11 -0800 | [diff] [blame] | 240 | Future<void> _flutterBuildAot(String relativePathToApplication) async { |
| 241 | print('Running AOT build tests...'); |
| 242 | await runCommand(flutter, |
| 243 | <String>['build', 'aot', '-v'], |
Yegor | 8d64301 | 2018-10-08 12:38:46 -0700 | [diff] [blame] | 244 | workingDirectory: path.join(flutterRoot, relativePathToApplication), |
| 245 | expectNonZeroExit: false, |
| 246 | timeout: _kShortTimeout, |
| 247 | ); |
Dan Field | 72926bd | 2018-11-29 09:32:11 -0800 | [diff] [blame] | 248 | print('Done.'); |
| 249 | } |
| 250 | |
| 251 | Future<void> _flutterBuildApk(String relativePathToApplication) async { |
Danny Tuppeny | c19142d | 2018-12-17 17:29:09 +0000 | [diff] [blame] | 252 | if ( |
| 253 | (Platform.environment['ANDROID_HOME']?.isEmpty ?? true) && |
| 254 | (Platform.environment['ANDROID_SDK_ROOT']?.isEmpty ?? true)) { |
Dan Field | 72926bd | 2018-11-29 09:32:11 -0800 | [diff] [blame] | 255 | return; |
| 256 | } |
| 257 | print('Running APK build tests...'); |
| 258 | await runCommand(flutter, |
| 259 | <String>['build', 'apk', '--debug', '-v'], |
| 260 | workingDirectory: path.join(flutterRoot, relativePathToApplication), |
| 261 | expectNonZeroExit: false, |
| 262 | timeout: _kShortTimeout, |
| 263 | ); |
| 264 | print('Done.'); |
| 265 | } |
| 266 | |
| 267 | Future<void> _flutterBuildIpa(String relativePathToApplication) async { |
| 268 | if (!Platform.isMacOS) { |
| 269 | return; |
| 270 | } |
| 271 | print('Running IPA build tests...'); |
| 272 | // Install Cocoapods. We don't have these checked in for the examples, |
| 273 | // and build ios doesn't take care of it automatically. |
| 274 | final File podfile = File(path.join(flutterRoot, relativePathToApplication, 'ios', 'Podfile')); |
| 275 | if (podfile.existsSync()) { |
| 276 | await runCommand('pod', |
| 277 | <String>['install'], |
| 278 | workingDirectory: podfile.parent.path, |
| 279 | expectNonZeroExit: false, |
| 280 | timeout: _kShortTimeout, |
| 281 | ); |
| 282 | } |
| 283 | await runCommand(flutter, |
| 284 | <String>['build', 'ios', '--no-codesign', '--debug', '-v'], |
| 285 | workingDirectory: path.join(flutterRoot, relativePathToApplication), |
| 286 | expectNonZeroExit: false, |
| 287 | timeout: _kShortTimeout, |
| 288 | ); |
| 289 | print('Done.'); |
Yegor | 8d64301 | 2018-10-08 12:38:46 -0700 | [diff] [blame] | 290 | } |
| 291 | |
Dan Field | b484a91 | 2019-02-23 09:56:27 -0800 | [diff] [blame] | 292 | Future<void> _runAdd2AppTest() async { |
| 293 | if (!Platform.isMacOS) { |
| 294 | return; |
| 295 | } |
| 296 | print('Running Add2App iOS integration tests...'); |
| 297 | final String add2AppDir = path.join(flutterRoot, 'dev', 'integration_tests', 'ios_add2app'); |
| 298 | await runCommand('./build_and_test.sh', |
| 299 | <String>[], |
| 300 | workingDirectory: add2AppDir, |
| 301 | expectNonZeroExit: false, |
| 302 | timeout: _kShortTimeout, |
| 303 | ); |
| 304 | print('Done.'); |
| 305 | } |
| 306 | |
Alexandre Ardhuin | d340e2f | 2018-10-04 18:44:23 +0200 | [diff] [blame] | 307 | Future<void> _runTests() async { |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 308 | final bq.BigqueryApi bigqueryApi = await _getBigqueryApi(); |
Greg Spencer | 90a5f46 | 2018-07-20 10:21:34 -0700 | [diff] [blame] | 309 | await _runSmokeTests(); |
| 310 | |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 311 | await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter'), tableData: bigqueryApi?.tabledata); |
Jacob Richman | b21fb8c | 2018-10-23 14:10:53 -0700 | [diff] [blame] | 312 | // Only packages/flutter/test/widgets/widget_inspector_test.dart really |
| 313 | // needs to be run with --track-widget-creation but it is nice to run |
| 314 | // all of the tests in package:flutter with the flag to ensure that |
| 315 | // the Dart kernel transformer triggered by the flag does not break anything. |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 316 | await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter'), options: <String>['--track-widget-creation'], tableData: bigqueryApi?.tabledata); |
| 317 | await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), tableData: bigqueryApi?.tabledata); |
| 318 | await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tableData: bigqueryApi?.tabledata); |
| 319 | await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), tableData: bigqueryApi?.tabledata); |
| 320 | await _runFlutterTest(path.join(flutterRoot, 'packages', 'fuchsia_remote_debug_protocol'), tableData: bigqueryApi?.tabledata); |
| 321 | await _pubRunTest(path.join(flutterRoot, 'dev', 'bots'), tableData: bigqueryApi?.tabledata); |
| 322 | await _pubRunTest(path.join(flutterRoot, 'dev', 'devicelab'), tableData: bigqueryApi?.tabledata); |
| 323 | await _pubRunTest(path.join(flutterRoot, 'dev', 'snippets'), tableData: bigqueryApi?.tabledata); |
| 324 | await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'), tableData: bigqueryApi?.tabledata); |
| 325 | await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests'), tableData: bigqueryApi?.tabledata); |
| 326 | await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'vitool'), tableData: bigqueryApi?.tabledata); |
| 327 | await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world'), tableData: bigqueryApi?.tabledata); |
| 328 | await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'), tableData: bigqueryApi?.tabledata); |
| 329 | await _runFlutterTest(path.join(flutterRoot, 'examples', 'stocks'), tableData: bigqueryApi?.tabledata); |
| 330 | await _runFlutterTest(path.join(flutterRoot, 'examples', 'flutter_gallery'), tableData: bigqueryApi?.tabledata); |
Jacob Richman | b21fb8c | 2018-10-23 14:10:53 -0700 | [diff] [blame] | 331 | // Regression test to ensure that code outside of package:flutter can run |
| 332 | // with --track-widget-creation. |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 333 | await _runFlutterTest(path.join(flutterRoot, 'examples', 'flutter_gallery'), options: <String>['--track-widget-creation'], tableData: bigqueryApi?.tabledata); |
| 334 | await _runFlutterTest(path.join(flutterRoot, 'examples', 'catalog'), tableData: bigqueryApi?.tabledata); |
Jonah Williams | 7bed378 | 2019-03-14 17:12:40 -0700 | [diff] [blame] | 335 | // Smoke test for code generation. |
| 336 | await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'codegen'), tableData: bigqueryApi?.tabledata, environment: <String, String>{ |
| 337 | 'FLUTTER_EXPERIMENTAL_BUILD': 'true', |
| 338 | }); |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 339 | |
| 340 | print('${bold}DONE: All tests successful.$reset'); |
| 341 | } |
| 342 | |
Alexandre Ardhuin | d340e2f | 2018-10-04 18:44:23 +0200 | [diff] [blame] | 343 | Future<void> _runCoverage() async { |
Siva | cf18d01 | 2018-10-19 06:19:24 -0700 | [diff] [blame] | 344 | final File coverageFile = File(path.join(flutterRoot, 'packages', 'flutter', 'coverage', 'lcov.info')); |
| 345 | if (!coverageFile.existsSync()) { |
| 346 | print('${red}Coverage file not found.$reset'); |
| 347 | print('Expected to find: ${coverageFile.absolute}'); |
| 348 | print('This file is normally obtained by running `flutter update-packages`.'); |
| 349 | exit(1); |
| 350 | } |
| 351 | coverageFile.deleteSync(); |
| 352 | await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter'), |
| 353 | options: const <String>['--coverage'], |
| 354 | ); |
| 355 | if (!coverageFile.existsSync()) { |
| 356 | print('${red}Coverage file not found.$reset'); |
| 357 | print('Expected to find: ${coverageFile.absolute}'); |
| 358 | print('This file should have been generated by the `flutter test --coverage` script, but was not.'); |
| 359 | exit(1); |
| 360 | } |
Todd Volkert | bd67926 | 2017-06-15 17:54:45 -0700 | [diff] [blame] | 361 | |
Siva | cf18d01 | 2018-10-19 06:19:24 -0700 | [diff] [blame] | 362 | print('${bold}DONE: Coverage collection successful.$reset'); |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 363 | } |
| 364 | |
Jonah Williams | d91cfff | 2019-03-01 19:18:38 -0800 | [diff] [blame] | 365 | Future<void> _buildRunnerTest( |
| 366 | String workingDirectory, |
| 367 | String flutterRoot, { |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 368 | String testPath, |
| 369 | bool enableFlutterToolAsserts = false, |
| 370 | bq.TabledataResourceApi tableData, |
| 371 | }) async { |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 372 | final List<String> args = <String>['run', 'build_runner', 'test', '--', useFlutterTestFormatter ? '-rjson' : '-rcompact', '-j1']; |
Jonah Williams | d91cfff | 2019-03-01 19:18:38 -0800 | [diff] [blame] | 373 | if (!hasColor) { |
| 374 | args.add('--no-color'); |
| 375 | } |
| 376 | if (testPath != null) { |
| 377 | args.add(testPath); |
| 378 | } |
| 379 | final Map<String, String> pubEnvironment = <String, String>{ |
| 380 | 'FLUTTER_ROOT': flutterRoot, |
| 381 | }; |
| 382 | if (Directory(pubCache).existsSync()) { |
| 383 | pubEnvironment['PUB_CACHE'] = pubCache; |
| 384 | } |
| 385 | if (enableFlutterToolAsserts) { |
| 386 | // If an existing env variable exists append to it, but only if |
| 387 | // it doesn't appear to already include enable-asserts. |
| 388 | String toolsArgs = Platform.environment['FLUTTER_TOOL_ARGS'] ?? ''; |
| 389 | if (!toolsArgs.contains('--enable-asserts')) |
| 390 | toolsArgs += ' --enable-asserts'; |
| 391 | pubEnvironment['FLUTTER_TOOL_ARGS'] = toolsArgs.trim(); |
| 392 | } |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 393 | |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 394 | if (useFlutterTestFormatter) { |
| 395 | final FlutterCompactFormatter formatter = FlutterCompactFormatter(); |
| 396 | final Stream<String> testOutput = runAndGetStdout( |
| 397 | pub, |
| 398 | args, |
| 399 | workingDirectory: workingDirectory, |
| 400 | environment: pubEnvironment, |
| 401 | beforeExit: formatter.finish |
| 402 | ); |
| 403 | await _processTestOutput(formatter, testOutput, tableData); |
| 404 | } else { |
| 405 | await runCommand( |
| 406 | pub, |
| 407 | args, |
| 408 | workingDirectory:workingDirectory, |
| 409 | environment:pubEnvironment, |
| 410 | ); |
| 411 | } |
Jonah Williams | d91cfff | 2019-03-01 19:18:38 -0800 | [diff] [blame] | 412 | } |
| 413 | |
Alexandre Ardhuin | d340e2f | 2018-10-04 18:44:23 +0200 | [diff] [blame] | 414 | Future<void> _pubRunTest( |
Todd Volkert | 1ada132 | 2017-03-09 12:58:31 -0800 | [diff] [blame] | 415 | String workingDirectory, { |
| 416 | String testPath, |
Alexandre Ardhuin | 387f885 | 2019-03-01 08:17:55 +0100 | [diff] [blame] | 417 | bool enableFlutterToolAsserts = false, |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 418 | bq.TabledataResourceApi tableData, |
| 419 | }) async { |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 420 | final List<String> args = <String>['run', 'test', useFlutterTestFormatter ? '-rjson' : '-rcompact', '-j1']; |
Ian Hickson | e342755 | 2018-06-04 15:22:19 -0700 | [diff] [blame] | 421 | if (!hasColor) |
| 422 | args.add('--no-color'); |
Todd Volkert | 1ada132 | 2017-03-09 12:58:31 -0800 | [diff] [blame] | 423 | if (testPath != null) |
| 424 | args.add(testPath); |
Leaf Petersen | ab874da | 2018-01-10 14:31:28 -0800 | [diff] [blame] | 425 | final Map<String, String> pubEnvironment = <String, String>{}; |
Alexandre Ardhuin | d927c93 | 2018-09-12 08:29:29 +0200 | [diff] [blame] | 426 | if (Directory(pubCache).existsSync()) { |
Greg Spencer | f29ecba | 2017-12-05 14:46:39 -0800 | [diff] [blame] | 427 | pubEnvironment['PUB_CACHE'] = pubCache; |
| 428 | } |
Danny Tuppeny | dc5a5c1 | 2018-08-23 20:49:59 +0100 | [diff] [blame] | 429 | if (enableFlutterToolAsserts) { |
| 430 | // If an existing env variable exists append to it, but only if |
| 431 | // it doesn't appear to already include enable-asserts. |
| 432 | String toolsArgs = Platform.environment['FLUTTER_TOOL_ARGS'] ?? ''; |
| 433 | if (!toolsArgs.contains('--enable-asserts')) |
| 434 | toolsArgs += ' --enable-asserts'; |
| 435 | pubEnvironment['FLUTTER_TOOL_ARGS'] = toolsArgs.trim(); |
| 436 | } |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 437 | if (useFlutterTestFormatter) { |
| 438 | final FlutterCompactFormatter formatter = FlutterCompactFormatter(); |
| 439 | final Stream<String> testOutput = runAndGetStdout( |
| 440 | pub, |
| 441 | args, |
| 442 | workingDirectory: workingDirectory, |
| 443 | beforeExit: formatter.finish, |
| 444 | ); |
| 445 | await _processTestOutput(formatter, testOutput, tableData); |
| 446 | } else { |
| 447 | await runCommand( |
| 448 | pub, |
| 449 | args, |
| 450 | workingDirectory:workingDirectory, |
| 451 | ); |
| 452 | } |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 453 | } |
| 454 | |
| 455 | enum CiProviders { |
| 456 | cirrus, |
| 457 | luci, |
| 458 | } |
| 459 | |
| 460 | CiProviders _getCiProvider() { |
| 461 | if (Platform.environment['CIRRUS_CI'] == 'true') { |
| 462 | return CiProviders.cirrus; |
| 463 | } |
| 464 | if (Platform.environment['LUCI_CONTEXT'] != null) { |
| 465 | return CiProviders.luci; |
| 466 | } |
| 467 | return null; |
| 468 | } |
| 469 | |
| 470 | String _getCiProviderName() { |
| 471 | switch(_getCiProvider()) { |
| 472 | case CiProviders.cirrus: |
| 473 | return 'cirrusci'; |
| 474 | case CiProviders.luci: |
| 475 | return 'luci'; |
| 476 | } |
| 477 | return 'unknown'; |
| 478 | } |
| 479 | |
| 480 | int _getPrNumber() { |
| 481 | switch(_getCiProvider()) { |
| 482 | case CiProviders.cirrus: |
Dan Field | e5b1ed7 | 2019-03-06 14:23:37 -0800 | [diff] [blame] | 483 | return Platform.environment['CIRRUS_PR'] == null |
| 484 | ? -1 |
| 485 | : int.tryParse(Platform.environment['CIRRUS_PR']); |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 486 | case CiProviders.luci: |
| 487 | return -1; // LUCI doesn't know about this. |
| 488 | } |
| 489 | return -1; |
| 490 | } |
| 491 | |
| 492 | Future<String> _getAuthors() async { |
| 493 | final String exe = Platform.isWindows ? '.exe' : ''; |
| 494 | final String author = await runAndGetStdout( |
| 495 | 'git$exe', <String>['log', _getGitHash(), '--pretty="%an <%ae>"'], |
| 496 | workingDirectory: flutterRoot, |
| 497 | ).first; |
| 498 | return author; |
| 499 | } |
| 500 | |
| 501 | String _getCiUrl() { |
| 502 | switch(_getCiProvider()) { |
| 503 | case CiProviders.cirrus: |
| 504 | return 'https://cirrus-ci.com/task/${Platform.environment['CIRRUS_TASK_ID']}'; |
| 505 | case CiProviders.luci: |
| 506 | return 'https://ci.chromium.org/p/flutter/g/framework/console'; // TODO(dnfield): can we get a direct link to the actual build? |
| 507 | } |
| 508 | return ''; |
| 509 | } |
| 510 | |
| 511 | String _getGitHash() { |
| 512 | switch(_getCiProvider()) { |
| 513 | case CiProviders.cirrus: |
| 514 | return Platform.environment['CIRRUS_CHANGE_IN_REPO']; |
| 515 | case CiProviders.luci: |
| 516 | return 'HEAD'; // TODO(dnfield): Set this in the env for LUCI. |
| 517 | } |
| 518 | return ''; |
| 519 | } |
| 520 | |
Dan Field | f67a529 | 2019-03-07 11:31:35 -0800 | [diff] [blame] | 521 | Future<void> _processTestOutput( |
| 522 | FlutterCompactFormatter formatter, |
| 523 | Stream<String> testOutput, |
| 524 | bq.TabledataResourceApi tableData, |
| 525 | ) async { |
Dan Field | 3af88c5 | 2019-03-08 16:12:27 -0800 | [diff] [blame] | 526 | final Timer heartbeat = Timer.periodic(const Duration(seconds: 30), (Timer timer) { |
| 527 | print('Processing...'); |
| 528 | }); |
| 529 | |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 530 | await testOutput.forEach(formatter.processRawOutput); |
Dan Field | 3af88c5 | 2019-03-08 16:12:27 -0800 | [diff] [blame] | 531 | heartbeat.cancel(); |
Dan Field | f67a529 | 2019-03-07 11:31:35 -0800 | [diff] [blame] | 532 | formatter.finish(); |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 533 | if (tableData == null || formatter.tests.isEmpty) { |
| 534 | return; |
| 535 | } |
| 536 | final bq.TableDataInsertAllRequest request = bq.TableDataInsertAllRequest(); |
| 537 | final String authors = await _getAuthors(); |
| 538 | request.rows = List<bq.TableDataInsertAllRequestRows>.from( |
| 539 | formatter.tests.map<bq.TableDataInsertAllRequestRows>((TestResult result) => |
| 540 | bq.TableDataInsertAllRequestRows.fromJson(<String, dynamic> { |
| 541 | 'json': <String, dynamic>{ |
| 542 | 'source': <String, dynamic>{ |
| 543 | 'provider': _getCiProviderName(), |
| 544 | 'url': _getCiUrl(), |
| 545 | 'platform': <String, dynamic>{ |
| 546 | 'os': Platform.operatingSystem, |
| 547 | 'version': Platform.operatingSystemVersion, |
| 548 | }, |
| 549 | }, |
| 550 | 'test': <String, dynamic>{ |
| 551 | 'name': result.name, |
| 552 | 'result': result.status.toString(), |
| 553 | 'file': result.path, |
| 554 | 'line': result.line, |
| 555 | 'column': result.column, |
| 556 | 'time': result.totalTime, |
| 557 | }, |
| 558 | 'git': <String, dynamic>{ |
| 559 | 'author': authors, |
| 560 | 'pull_request': _getPrNumber(), |
| 561 | 'commit': _getGitHash(), |
| 562 | 'organization': 'flutter', |
| 563 | 'repository': 'flutter', |
| 564 | }, |
| 565 | 'error': result.status != TestStatus.failed ? null : <String, dynamic>{ |
| 566 | 'message': result.errorMessage, |
| 567 | 'stack_trace': result.stackTrace, |
| 568 | }, |
| 569 | 'information': result.messages, |
| 570 | }, |
| 571 | }), |
| 572 | ), |
| 573 | growable: false, |
| 574 | ); |
| 575 | final bq.TableDataInsertAllResponse response = await tableData.insertAll(request, 'flutter-infra', 'tests', 'ci'); |
| 576 | if (response.insertErrors != null && response.insertErrors.isNotEmpty) { |
| 577 | print('${red}BigQuery insert errors:'); |
| 578 | print(response.toJson()); |
| 579 | print(reset); |
| 580 | } |
Todd Volkert | 1ada132 | 2017-03-09 12:58:31 -0800 | [diff] [blame] | 581 | } |
| 582 | |
Yegor | f4f20c2 | 2017-09-22 12:26:47 -0700 | [diff] [blame] | 583 | class EvalResult { |
| 584 | EvalResult({ |
| 585 | this.stdout, |
| 586 | this.stderr, |
Greg Spencer | 1a41499 | 2018-07-25 15:19:57 -0700 | [diff] [blame] | 587 | this.exitCode = 0, |
Yegor | f4f20c2 | 2017-09-22 12:26:47 -0700 | [diff] [blame] | 588 | }); |
| 589 | |
| 590 | final String stdout; |
| 591 | final String stderr; |
Greg Spencer | 1a41499 | 2018-07-25 15:19:57 -0700 | [diff] [blame] | 592 | final int exitCode; |
Yegor | f4f20c2 | 2017-09-22 12:26:47 -0700 | [diff] [blame] | 593 | } |
| 594 | |
Alexandre Ardhuin | d340e2f | 2018-10-04 18:44:23 +0200 | [diff] [blame] | 595 | Future<void> _runFlutterTest(String workingDirectory, { |
Todd Volkert | 58d3493 | 2018-04-17 10:00:06 -0700 | [diff] [blame] | 596 | String script, |
Alexandre Ardhuin | 09276be | 2018-06-05 08:50:40 +0200 | [diff] [blame] | 597 | bool expectFailure = false, |
| 598 | bool printOutput = true, |
| 599 | List<String> options = const <String>[], |
| 600 | bool skip = false, |
| 601 | Duration timeout = _kLongTimeout, |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 602 | bq.TabledataResourceApi tableData, |
Jonah Williams | 7bed378 | 2019-03-14 17:12:40 -0700 | [diff] [blame] | 603 | Map<String, String> environment, |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 604 | }) async { |
Chris Bracken | 6c97dd2 | 2017-03-03 18:06:08 -0800 | [diff] [blame] | 605 | final List<String> args = <String>['test']..addAll(options); |
Ian Hickson | aaa0a1c | 2017-04-13 10:22:41 -0700 | [diff] [blame] | 606 | if (flutterTestArgs != null && flutterTestArgs.isNotEmpty) |
Alexander Thomas | 425bd5a | 2017-12-09 00:49:29 +0100 | [diff] [blame] | 607 | args.addAll(flutterTestArgs); |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 608 | |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 609 | final bool shouldProcessOutput = useFlutterTestFormatter && !expectFailure && !options.contains('--coverage'); |
Dan Field | f67a529 | 2019-03-07 11:31:35 -0800 | [diff] [blame] | 610 | if (shouldProcessOutput) { |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 611 | args.add('--machine'); |
| 612 | } |
| 613 | |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 614 | if (script != null) { |
| 615 | final String fullScriptPath = path.join(workingDirectory, script); |
| 616 | if (!FileSystemEntity.isFileSync(fullScriptPath)) { |
| 617 | print('Could not find test: $fullScriptPath'); |
| 618 | print('Working directory: $workingDirectory'); |
| 619 | print('Script: $script'); |
| 620 | if (!printOutput) |
| 621 | print('This is one of the tests that does not normally print output.'); |
| 622 | if (skip) |
| 623 | print('This is one of the tests that is normally skipped in this configuration.'); |
| 624 | exit(1); |
| 625 | } |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 626 | args.add(script); |
Ian Hickson | dac2ebf | 2018-06-11 16:28:01 -0700 | [diff] [blame] | 627 | } |
Dan Field | f67a529 | 2019-03-07 11:31:35 -0800 | [diff] [blame] | 628 | if (!shouldProcessOutput) { |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 629 | return runCommand(flutter, args, |
| 630 | workingDirectory: workingDirectory, |
Dan Field | a3b484d | 2019-03-07 18:59:43 -0800 | [diff] [blame] | 631 | expectNonZeroExit: expectFailure, |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 632 | printOutput: printOutput, |
| 633 | skip: skip, |
| 634 | timeout: timeout, |
Jonah Williams | 7bed378 | 2019-03-14 17:12:40 -0700 | [diff] [blame] | 635 | environment: environment, |
Dan Field | 20e0f13 | 2019-03-06 13:13:45 -0800 | [diff] [blame] | 636 | ); |
| 637 | } |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 638 | |
| 639 | if (useFlutterTestFormatter) { |
Dan Field | f67a529 | 2019-03-07 11:31:35 -0800 | [diff] [blame] | 640 | final FlutterCompactFormatter formatter = FlutterCompactFormatter(); |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 641 | final Stream<String> testOutput = runAndGetStdout( |
| 642 | flutter, |
| 643 | args, |
Adam Barth | a44d3b7 | 2017-02-16 20:40:07 -0800 | [diff] [blame] | 644 | workingDirectory: workingDirectory, |
Greg Spencer | f44f625 | 2018-07-23 15:41:31 -0700 | [diff] [blame] | 645 | expectNonZeroExit: expectFailure, |
Todd Volkert | 58d3493 | 2018-04-17 10:00:06 -0700 | [diff] [blame] | 646 | timeout: timeout, |
Dan Field | f67a529 | 2019-03-07 11:31:35 -0800 | [diff] [blame] | 647 | beforeExit: formatter.finish, |
Jonah Williams | 7bed378 | 2019-03-14 17:12:40 -0700 | [diff] [blame] | 648 | environment: environment, |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 649 | ); |
Dan Field | f67a529 | 2019-03-07 11:31:35 -0800 | [diff] [blame] | 650 | await _processTestOutput(formatter, testOutput, tableData); |
Dan Field | 97a8120 | 2019-03-14 08:26:59 -0700 | [diff] [blame] | 651 | } else { |
| 652 | await runCommand( |
| 653 | flutter, |
| 654 | args, |
| 655 | workingDirectory: workingDirectory, |
| 656 | expectNonZeroExit: expectFailure, |
| 657 | timeout: timeout, |
| 658 | ); |
| 659 | } |
Michael Goderbauer | 7696462 | 2017-02-14 10:21:33 -0800 | [diff] [blame] | 660 | } |
| 661 | |
Alexandre Ardhuin | d340e2f | 2018-10-04 18:44:23 +0200 | [diff] [blame] | 662 | Future<void> _verifyVersion(String filename) async { |
Alexandre Ardhuin | d927c93 | 2018-09-12 08:29:29 +0200 | [diff] [blame] | 663 | if (!File(filename).existsSync()) { |
Greg Spencer | 977da4f | 2018-08-24 14:06:25 -0700 | [diff] [blame] | 664 | print('$redLine'); |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 665 | print('The version logic failed to create the Flutter version file.'); |
Greg Spencer | 977da4f | 2018-08-24 14:06:25 -0700 | [diff] [blame] | 666 | print('$redLine'); |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 667 | exit(1); |
| 668 | } |
Alexandre Ardhuin | d927c93 | 2018-09-12 08:29:29 +0200 | [diff] [blame] | 669 | final String version = await File(filename).readAsString(); |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 670 | if (version == '0.0.0-unknown') { |
Greg Spencer | 977da4f | 2018-08-24 14:06:25 -0700 | [diff] [blame] | 671 | print('$redLine'); |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 672 | print('The version logic failed to determine the Flutter version.'); |
Greg Spencer | 977da4f | 2018-08-24 14:06:25 -0700 | [diff] [blame] | 673 | print('$redLine'); |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 674 | exit(1); |
| 675 | } |
Alexandre Ardhuin | d927c93 | 2018-09-12 08:29:29 +0200 | [diff] [blame] | 676 | final RegExp pattern = RegExp(r'^[0-9]+\.[0-9]+\.[0-9]+(-pre\.[0-9]+)?$'); |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 677 | if (!version.contains(pattern)) { |
Greg Spencer | 977da4f | 2018-08-24 14:06:25 -0700 | [diff] [blame] | 678 | print('$redLine'); |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 679 | print('The version logic generated an invalid version string.'); |
Greg Spencer | 977da4f | 2018-08-24 14:06:25 -0700 | [diff] [blame] | 680 | print('$redLine'); |
Ian Hickson | 64e2e00 | 2018-01-26 16:59:56 -0800 | [diff] [blame] | 681 | exit(1); |
| 682 | } |
Vyacheslav Egorov | 71b2cfb | 2018-03-16 20:29:38 +0100 | [diff] [blame] | 683 | } |
Dan Field | 2a644f3 | 2019-03-10 07:52:44 -0700 | [diff] [blame] | 684 | |
| 685 | Future<void> _runIntegrationTests() async { |
| 686 | print('Platform env vars:'); |
| 687 | |
| 688 | await _runDevicelabTest('dartdocs'); |
| 689 | |
| 690 | if (Platform.isLinux) { |
| 691 | await _runDevicelabTest('flutter_create_offline_test_linux'); |
| 692 | } else if (Platform.isWindows) { |
| 693 | await _runDevicelabTest('flutter_create_offline_test_windows'); |
| 694 | } else if (Platform.isMacOS) { |
| 695 | await _runDevicelabTest('flutter_create_offline_test_mac'); |
| 696 | await _runDevicelabTest('module_test_ios'); |
| 697 | } |
| 698 | await _integrationTestsAndroidSdk(); |
| 699 | } |
| 700 | |
| 701 | Future<void> _runDevicelabTest(String testName, {Map<String, String> env}) async { |
| 702 | await runCommand( |
| 703 | dart, |
| 704 | <String>['bin/run.dart', '-t', testName], |
| 705 | workingDirectory: path.join(flutterRoot, 'dev', 'devicelab'), |
| 706 | environment: env, |
| 707 | ); |
| 708 | } |
| 709 | |
| 710 | Future<void> _integrationTestsAndroidSdk() async { |
| 711 | final String androidSdkRoot = (Platform.environment['ANDROID_HOME']?.isEmpty ?? true) |
| 712 | ? Platform.environment['ANDROID_SDK_ROOT'] |
| 713 | : Platform.environment['ANDROID_HOME']; |
| 714 | if (androidSdkRoot == null || androidSdkRoot.isEmpty) { |
| 715 | print('No Android SDK detected, skipping Android Integration Tests'); |
| 716 | return; |
| 717 | } |
| 718 | |
| 719 | final Map<String, String> env = <String, String> { |
| 720 | 'ANDROID_HOME': androidSdkRoot, |
| 721 | 'ANDROID_SDK_ROOT': androidSdkRoot, |
| 722 | }; |
| 723 | |
| 724 | // TODO(dnfield): gradlew is crashing on the cirrus image and it's not clear why. |
| 725 | if (!Platform.isWindows) { |
| 726 | await _runDevicelabTest('gradle_plugin_test', env: env); |
| 727 | await _runDevicelabTest('module_test', env: env); |
| 728 | } |
| 729 | // note: this also covers plugin_test_win as long as Windows has an Android SDK available. |
| 730 | await _runDevicelabTest('plugin_test', env: env); |
Jonah Williams | 72605d2 | 2019-03-15 19:33:24 -0700 | [diff] [blame] | 731 | } |