[flutter_tools] make local engine integration testing easier (#65802)

diff --git a/packages/flutter_tools/README.md b/packages/flutter_tools/README.md
index bccbfe5..bd644ff 100644
--- a/packages/flutter_tools/README.md
+++ b/packages/flutter_tools/README.md
@@ -22,7 +22,7 @@
 
 To run Flutter Tools from source, in this directory run:
 ```shell
-$ ../../bin/cache/dart-sdk/bin/dart bin/flutter_tools.dart
+$ ../../bin/dart bin/flutter_tools.dart
 ```
 followed by command-line arguments, as usual.
 
@@ -56,24 +56,38 @@
 of the diff should be close to the average coverage, and should ideally be
 better.
 
+#### Using local engine builds in integration tests
+
+The integration tests can be configured to use a specific local engine
+variant by setting the `FLUTTER_LOCAL_ENGINE` environment variable to the
+name of the local engine (e.g. "android_debug_unopt"). If the local engine build
+requires a source path, this can be provided by setting the `FLUTTER_LOCAL_ENGINE_SRC_PATH`
+environment variable. This second variable is not necessary if the `flutter` and
+`engine` checkouts are in adjacent directories.
+
+```shell
+export FLUTTER_LOCAL_ENGINE=android_debug_unopt
+../../bin/dart test test/integration.shard/some_test_case
+```
+
 ### Running the tests
 
 To run the tests in the `test/` directory, first ensure that there are no
 connected devices. Then, in this directory run:
 ```shell
-$ ../../bin/cache/dart-sdk/bin/pub run test
+$ ../../bin/dart pub run test
 ```
 
 The tests in `test/integration.shard` are slower to run than the tests in
 `test/general.shard`. To run only the tests in `test/general.shard`, in this
 directory run:
 ```shell
-$ ../../bin/cache/dart-sdk/bin/pub run test test/general.shard
+$ ../../bin/dart pub run test test/general.shard
 ```
 
 To run the tests in a specific file, run:
 ```shell
-$ ../../bin/cache/dart-sdk/bin/pub run test test/general.shard/utils_test.dart
+$ ../../bin/dart pub run test test/general.shard/utils_test.dart
 ```
 
 ### Forcing snapshot regeneration
diff --git a/packages/flutter_tools/test/integration.shard/analyze_size_test.dart b/packages/flutter_tools/test/integration.shard/analyze_size_test.dart
index db284c7..888de26 100644
--- a/packages/flutter_tools/test/integration.shard/analyze_size_test.dart
+++ b/packages/flutter_tools/test/integration.shard/analyze_size_test.dart
@@ -18,6 +18,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+      ...getLocalEngineArguments(),
       'build',
       'apk',
       '--analyze-size',
@@ -42,6 +43,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+       ...getLocalEngineArguments(),
       'build',
       'ios',
       '--analyze-size',
@@ -65,6 +67,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+       ...getLocalEngineArguments(),
       'build',
       'apk',
       '--analyze-size',
diff --git a/packages/flutter_tools/test/integration.shard/build_ios_config_only_test.dart b/packages/flutter_tools/test/integration.shard/build_ios_config_only_test.dart
index 494cd71..d3da2aa 100644
--- a/packages/flutter_tools/test/integration.shard/build_ios_config_only_test.dart
+++ b/packages/flutter_tools/test/integration.shard/build_ios_config_only_test.dart
@@ -5,23 +5,23 @@
 import 'package:file_testing/file_testing.dart';
 import 'package:flutter_tools/src/base/file_system.dart';
 import 'package:flutter_tools/src/base/io.dart';
-import 'package:flutter_tools/src/base/platform.dart';
-import 'package:process/process.dart';
-import 'package:flutter_tools/src/globals.dart' as globals;
 
 import '../src/common.dart';
+import 'test_utils.dart';
 
 void main() {
   test('flutter build ios --config only updates generated xcconfig file without performing build', () async {
-    final String woringDirectory = globals.fs.path.join(getFlutterRoot(), 'examples', 'hello_world');
-    final String flutterBin = globals.fs.path.join(getFlutterRoot(), 'bin', 'flutter');
+    final String woringDirectory = fileSystem.path.join(getFlutterRoot(), 'examples', 'hello_world');
+    final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
 
-    await const LocalProcessManager().run(<String>[
+    await processManager.run(<String>[
       flutterBin,
+       ...getLocalEngineArguments(),
       'clean',
     ], workingDirectory: woringDirectory);
-    final ProcessResult result = await const LocalProcessManager().run(<String>[
+    final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+      ...getLocalEngineArguments(),
       'build',
       'ios',
       '--config-only',
@@ -36,20 +36,20 @@
 
     expect(result.exitCode, 0);
 
-    final File generatedConfig = globals.fs.file(
-      globals.fs.path.join(woringDirectory, 'ios', 'Flutter', 'Generated.xcconfig'));
+    final File generatedConfig = fileSystem.file(
+      fileSystem.path.join(woringDirectory, 'ios', 'Flutter', 'Generated.xcconfig'));
 
     // Config is updated if command succeeded.
     expect(generatedConfig, exists);
     expect(generatedConfig.readAsStringSync(), allOf(
       contains('DART_OBFUSCATION=true'),
-      contains('FLUTTER_FRAMEWORK_DIR=${globals.fs.path.absolute(getFlutterRoot(), 'bin', 'cache', 'artifacts', 'engine')}'),
+      contains('FLUTTER_FRAMEWORK_DIR=${fileSystem.path.absolute(getFlutterRoot(), 'bin', 'cache', 'artifacts', 'engine')}'),
     ));
 
     // file that only exists if app was fully built.
-    final File frameworkPlist = globals.fs.file(
-      globals.fs.path.join(woringDirectory, 'build', 'ios', 'iphoneos', 'Runner.app', 'AppFrameworkInfo.plist'));
+    final File frameworkPlist = fileSystem.file(
+      fileSystem.path.join(woringDirectory, 'build', 'ios', 'iphoneos', 'Runner.app', 'AppFrameworkInfo.plist'));
 
     expect(frameworkPlist, isNot(exists));
-  },skip: !const LocalPlatform().isMacOS);
+  }, skip: !platform.isMacOS);
 }
diff --git a/packages/flutter_tools/test/integration.shard/command_output_test.dart b/packages/flutter_tools/test/integration.shard/command_output_test.dart
index 698b13b..af49bb0 100644
--- a/packages/flutter_tools/test/integration.shard/command_output_test.dart
+++ b/packages/flutter_tools/test/integration.shard/command_output_test.dart
@@ -16,6 +16,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+      ...getLocalEngineArguments(),
       '-h',
       '-v',
     ]);
@@ -36,6 +37,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+      ...getLocalEngineArguments(),
       'doctor',
       '-v',
     ]);
@@ -48,6 +50,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+      ...getLocalEngineArguments(),
       'doctor',
       '-vv',
     ]);
@@ -60,6 +63,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+      ...getLocalEngineArguments(),
       'config',
     ]);
 
@@ -89,6 +93,7 @@
       final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
       final ProcessResult result = await processManager.run(<String>[
         flutterBin,
+        ...getLocalEngineArguments(),
         'run',
         '--show-test-device', // ensure command can fail to run and hit injection of correct logger.
         '--machine',
@@ -105,6 +110,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+      ...getLocalEngineArguments(),
       'attach',
       '--machine',
       '-v',
@@ -117,6 +123,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+      ...getLocalEngineArguments(),
       'build',
       '-h',
       '-v',
@@ -133,6 +140,7 @@
     final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
     final ProcessResult result = await processManager.run(<String>[
       flutterBin,
+      ...getLocalEngineArguments(),
       '--version',
       '--machine',
     ]);
diff --git a/packages/flutter_tools/test/integration.shard/daemon_mode_test.dart b/packages/flutter_tools/test/integration.shard/daemon_mode_test.dart
index 6932d46..c8c0154 100644
--- a/packages/flutter_tools/test/integration.shard/daemon_mode_test.dart
+++ b/packages/flutter_tools/test/integration.shard/daemon_mode_test.dart
@@ -27,7 +27,7 @@
 
     const ProcessManager processManager = LocalProcessManager();
     final Process process = await processManager.start(
-      <String>[flutterBin, '--show-test-device', 'daemon'],
+      <String>[flutterBin, ...getLocalEngineArguments(), '--show-test-device', 'daemon'],
       workingDirectory: tempDir.path,
     );
 
diff --git a/packages/flutter_tools/test/integration.shard/test_driver.dart b/packages/flutter_tools/test/integration.shard/test_driver.dart
index 1154ff5..8c57063 100644
--- a/packages/flutter_tools/test/integration.shard/test_driver.dart
+++ b/packages/flutter_tools/test/integration.shard/test_driver.dart
@@ -452,6 +452,7 @@
           '--disable-service-auth-codes',
         if (machine) '--machine',
         if (!spawnDdsInstance) '--disable-dds',
+        ...getLocalEngineArguments(),
         '-d',
         if (chrome)
           ...<String>[
@@ -482,6 +483,7 @@
     await _setupProcess(
       <String>[
         'attach',
+         ...getLocalEngineArguments(),
         '--machine',
         if (!spawnDdsInstance)
           '--disable-dds',
@@ -705,6 +707,7 @@
   }) async {
     await _setupProcess(<String>[
       'test',
+       ...getLocalEngineArguments(),
       '--disable-service-auth-codes',
       '--machine',
       if (coverage)
diff --git a/packages/flutter_tools/test/integration.shard/test_utils.dart b/packages/flutter_tools/test/integration.shard/test_utils.dart
index 50459cf..f6d3997 100644
--- a/packages/flutter_tools/test/integration.shard/test_utils.dart
+++ b/packages/flutter_tools/test/integration.shard/test_utils.dart
@@ -63,3 +63,15 @@
     throw Exception('flutter pub get failed: ${result.stderr}\n${result.stdout}');
   }
 }
+
+const String kLocalEngineEnvironment = 'FLUTTER_LOCAL_ENGINE';
+const String kLocalEngineLocation = 'FLUTTER_LOCAL_ENGINE_SRC_PATH';
+
+List<String> getLocalEngineArguments() {
+  return <String>[
+    if (platform.environment.containsKey(kLocalEngineEnvironment))
+      '--local-engine=${platform.environment[kLocalEngineEnvironment]}',
+    if (platform.environment.containsKey(kLocalEngineLocation))
+      '--local-engine-src-path=${platform.environment[kLocalEngineLocation]}',
+  ];
+}