From 555721de2410cff8e3f10c46c291b4636f72d80b Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 17 Feb 2021 17:00:12 -0800 Subject: [PATCH] [flutter_tools] remove mock process manager from gradle tests (#76252) --- .../flutter_tools/lib/src/android/gradle.dart | 98 ++- .../lib/src/application_package.dart | 2 +- .../flutter_tools/lib/src/context_runner.dart | 2 + .../android/android_gradle_builder_test.dart | 753 ++++++++++-------- .../general.shard/android/gradle_test.dart | 32 +- 5 files changed, 484 insertions(+), 403 deletions(-) diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart index 9f82250baa7..9caf4043b94 100644 --- a/packages/flutter_tools/lib/src/android/gradle.dart +++ b/packages/flutter_tools/lib/src/android/gradle.dart @@ -6,6 +6,7 @@ import 'package:crypto/crypto.dart'; import 'package:meta/meta.dart'; +import 'package:process/process.dart'; import 'package:xml/xml.dart'; import '../artifacts.dart'; @@ -21,7 +22,7 @@ import '../build_info.dart'; import '../cache.dart'; import '../convert.dart'; import '../flutter_manifest.dart'; -import '../globals.dart' as globals hide logger, printStatus, printTrace, printError; +import '../globals.dart' as globals hide logger, printStatus, printTrace, printError, processManager, processUtils, fs; import '../project.dart'; import '../reporting/reporting.dart'; import 'android_builder.dart'; @@ -108,13 +109,14 @@ Iterable _apkFilesFor(AndroidBuildInfo androidBuildInfo) { /// Returns true if the current version of the Gradle plugin is supported. bool _isSupportedVersion(AndroidProject project) { + final FileSystem fileSystem = project.hostAppGradleRoot.fileSystem; final File plugin = project.hostAppGradleRoot.childFile( - globals.fs.path.join('buildSrc', 'src', 'main', 'groovy', 'FlutterPlugin.groovy')); + fileSystem.path.join('buildSrc', 'src', 'main', 'groovy', 'FlutterPlugin.groovy')); if (plugin.existsSync()) { return false; } final File appGradle = project.hostAppGradleRoot.childFile( - globals.fs.path.join('app', 'build.gradle')); + fileSystem.path.join('app', 'build.gradle')); if (!appGradle.existsSync()) { return false; } @@ -137,12 +139,12 @@ Future getGradleAppOut(AndroidProject androidProject) async { /// Runs `gradlew dependencies`, ensuring that dependencies are resolved and /// potentially downloaded. -Future checkGradleDependencies(Logger logger) async { +Future checkGradleDependencies(Logger logger, ProcessUtils processUtils) async { final Status progress = logger.startProgress( 'Ensuring gradle dependencies are up to date...', ); final FlutterProject flutterProject = FlutterProject.current(); - await globals.processUtils.run([ + await processUtils.run([ globals.gradleUtils.getExecutable(flutterProject), 'dependencies', ], @@ -162,6 +164,7 @@ Future checkGradleDependencies(Logger logger) async { /// `settings.gradle` file has local edits. @visibleForTesting void createSettingsAarGradle(Directory androidDirectory, Logger logger) { + final FileSystem fileSystem = androidDirectory.fileSystem; final File newSettingsFile = androidDirectory.childFile('settings_aar.gradle'); if (newSettingsFile.existsSync()) { return; @@ -172,14 +175,14 @@ void createSettingsAarGradle(Directory androidDirectory, Logger logger) { } final String currentFileContent = currentSettingsFile.readAsStringSync(); - final String newSettingsRelativeFile = globals.fs.path.relative(newSettingsFile.path); + final String newSettingsRelativeFile = fileSystem.path.relative(newSettingsFile.path); final Status status = logger.startProgress('✏️ Creating `$newSettingsRelativeFile`...'); - final String flutterRoot = globals.fs.path.absolute(Cache.flutterRoot); - final File legacySettingsDotGradleFiles = globals.fs.file(globals.fs.path.join(flutterRoot, 'packages','flutter_tools', + final String flutterRoot = fileSystem.path.absolute(Cache.flutterRoot); + final File legacySettingsDotGradleFiles = fileSystem.file(fileSystem.path.join(flutterRoot, 'packages','flutter_tools', 'gradle', 'settings.gradle.legacy_versions')); assert(legacySettingsDotGradleFiles.existsSync()); - final String settingsAarContent = globals.fs.file(globals.fs.path.join(flutterRoot, 'packages','flutter_tools', + final String settingsAarContent = fileSystem.file(fileSystem.path.join(flutterRoot, 'packages','flutter_tools', 'gradle', 'settings_aar.gradle.tmpl')).readAsStringSync(); // Get the `settings.gradle` content variants that should be patched. @@ -197,7 +200,7 @@ void createSettingsAarGradle(Directory androidDirectory, Logger logger) { status.cancel(); logger.printStatus('$warningMark Flutter tried to create the file `$newSettingsRelativeFile`, but failed.'); // Print how to manually update the file. - logger.printStatus(globals.fs.file(globals.fs.path.join(flutterRoot, 'packages','flutter_tools', + logger.printStatus(fileSystem.file(fileSystem.path.join(flutterRoot, 'packages','flutter_tools', 'gradle', 'manual_migration_settings.gradle.md')).readAsStringSync()); throwToolExit('Please create the file and run this command again.'); } @@ -211,9 +214,15 @@ void createSettingsAarGradle(Directory androidDirectory, Logger logger) { class AndroidGradleBuilder implements AndroidBuilder { AndroidGradleBuilder({ @required Logger logger, - }) : _logger = logger; + @required ProcessManager processManager, + @required FileSystem fileSystem, + }) : _logger = logger, + _fileSystem = fileSystem, + _processUtils = ProcessUtils(logger: logger, processManager: processManager); final Logger _logger; + final ProcessUtils _processUtils; + final FileSystem _fileSystem; /// Builds the AAR and POM files for the current Flutter module or plugin. @override @@ -226,7 +235,7 @@ class AndroidGradleBuilder implements AndroidBuilder { }) async { try { Directory outputDirectory = - globals.fs.directory(outputDirectoryPath ?? project.android.buildDirectory); + _fileSystem.directory(outputDirectoryPath ?? project.android.buildDirectory); if (project.isModule) { // Module projects artifacts are located in `build/host`. outputDirectory = outputDirectory.childDirectory('host'); @@ -249,7 +258,7 @@ class AndroidGradleBuilder implements AndroidBuilder { repoDirectory: getRepoDirectory(outputDirectory), buildNumber: buildNumber, logger: _logger, - fileSystem: globals.fs, + fileSystem: _fileSystem, ); } finally { globals.androidSdk?.reinitialize(); @@ -383,6 +392,7 @@ class AndroidGradleBuilder implements AndroidBuilder { final Directory localEngineRepo = _getLocalEngineRepo( engineOutPath: localEngineArtifacts.engineOutPath, androidBuildInfo: androidBuildInfo, + fileSystem: _fileSystem, ); _logger.printTrace( 'Using local engine: ${localEngineArtifacts.engineOutPath}\n' @@ -454,7 +464,7 @@ class AndroidGradleBuilder implements AndroidBuilder { ..start(); int exitCode = 1; try { - exitCode = await globals.processUtils.stream( + exitCode = await _processUtils.stream( command, workingDirectory: project.android.hostAppGradleRoot.path, allowReentrantFlutter: true, @@ -542,7 +552,7 @@ class AndroidGradleBuilder implements AndroidBuilder { } _logger.printStatus( - '$successMark Built ${globals.fs.path.relative(bundleFile.path)}$appSize.', + '$successMark Built ${_fileSystem.path.relative(bundleFile.path)}$appSize.', color: TerminalColor.green, ); return; @@ -575,7 +585,7 @@ class AndroidGradleBuilder implements AndroidBuilder { ? '' // Don't display the size when building a debug variant. : ' (${getSizeAsMB(apkFile.lengthSync())})'; _logger.printStatus( - '$successMark Built ${globals.fs.path.relative(apkFile.path)}$appSize.', + '$successMark Built ${_fileSystem.path.relative(apkFile.path)}$appSize.', color: TerminalColor.green, ); @@ -588,15 +598,15 @@ class AndroidGradleBuilder implements AndroidBuilder { File zipFile, AndroidBuildInfo androidBuildInfo,) async { final SizeAnalyzer sizeAnalyzer = SizeAnalyzer( - fileSystem: globals.fs, + fileSystem: _fileSystem, logger: _logger, flutterUsage: globals.flutterUsage, ); final String archName = getNameForAndroidArch(androidBuildInfo.targetArchs.single); final BuildInfo buildInfo = androidBuildInfo.buildInfo; - final File aotSnapshot = globals.fs.directory(buildInfo.codeSizeDirectory) + final File aotSnapshot = _fileSystem.directory(buildInfo.codeSizeDirectory) .childFile('snapshot.$archName.json'); - final File precompilerTrace = globals.fs.directory(buildInfo.codeSizeDirectory) + final File precompilerTrace = _fileSystem.directory(buildInfo.codeSizeDirectory) .childFile('trace.$archName.json'); final Map output = await sizeAnalyzer.analyzeZipSizeAndAotSnapshot( zipFile: zipFile, @@ -605,9 +615,9 @@ class AndroidGradleBuilder implements AndroidBuilder { kind: kind, ); final File outputFile = globals.fsUtils.getUniqueFile( - globals.fs - .directory(globals.fsUtils.homeDirPath) - .childDirectory('.flutter-devtools'), '$kind-code-size-analysis', 'json', + _fileSystem + .directory(globals.fsUtils.homeDirPath) + .childDirectory('.flutter-devtools'), '$kind-code-size-analysis', 'json', ) ..writeAsStringSync(jsonEncode(output)); // This message is used as a sentinel in analyze_apk_size_test.dart @@ -658,8 +668,8 @@ class AndroidGradleBuilder implements AndroidBuilder { multilineOutput: true, ); - final String flutterRoot = globals.fs.path.absolute(Cache.flutterRoot); - final String initScript = globals.fs.path.join( + final String flutterRoot = _fileSystem.path.absolute(Cache.flutterRoot); + final String initScript = _fileSystem.path.join( flutterRoot, 'packages', 'flutter_tools', @@ -699,6 +709,7 @@ class AndroidGradleBuilder implements AndroidBuilder { final Directory localEngineRepo = _getLocalEngineRepo( engineOutPath: localEngineArtifacts.engineOutPath, androidBuildInfo: androidBuildInfo, + fileSystem: _fileSystem, ); _logger.printTrace( 'Using local engine: ${localEngineArtifacts.engineOutPath}\n' @@ -734,7 +745,7 @@ class AndroidGradleBuilder implements AndroidBuilder { ..start(); RunResult result; try { - result = await globals.processUtils.run( + result = await _processUtils.run( command, workingDirectory: project.android.hostAppGradleRoot.path, allowReentrantFlutter: true, @@ -766,7 +777,7 @@ class AndroidGradleBuilder implements AndroidBuilder { ); } _logger.printStatus( - '$successMark Built ${globals.fs.path.relative(repoDirectory.path)}.', + '$successMark Built ${_fileSystem.path.relative(repoDirectory.path)}.', color: TerminalColor.green, ); } @@ -788,7 +799,7 @@ class AndroidGradleBuilder implements AndroidBuilder { if (pluginParts.length != 2) { continue; } - final Directory pluginDirectory = globals.fs.directory(pluginParts.last); + final Directory pluginDirectory = _fileSystem.directory(pluginParts.last); assert(pluginDirectory.existsSync()); final String pluginName = pluginParts.first; @@ -1067,12 +1078,12 @@ void _exitWithExpectedFileNotFound({ ); } -void _createSymlink(String targetPath, String linkPath) { - final File targetFile = globals.fs.file(targetPath); +void _createSymlink(String targetPath, String linkPath, FileSystem fileSystem) { + final File targetFile = fileSystem.file(targetPath); if (!targetFile.existsSync()) { throwToolExit("The file $targetPath wasn't found in the local engine out directory."); } - final File linkFile = globals.fs.file(linkPath); + final File linkFile = fileSystem.file(linkPath); final Link symlink = linkFile.parent.childLink(linkFile.basename); try { symlink.createSync(targetPath, recursive: true); @@ -1083,8 +1094,8 @@ void _createSymlink(String targetPath, String linkPath) { } } -String _getLocalArtifactVersion(String pomPath) { - final File pomFile = globals.fs.file(pomPath); +String _getLocalArtifactVersion(String pomPath, FileSystem fileSystem) { + final File pomFile = fileSystem.file(pomPath); if (!pomFile.existsSync()) { throwToolExit("The file $pomPath wasn't found in the local engine out directory."); } @@ -1118,12 +1129,13 @@ String _getLocalArtifactVersion(String pomPath) { Directory _getLocalEngineRepo({ @required String engineOutPath, @required AndroidBuildInfo androidBuildInfo, + @required FileSystem fileSystem, }) { assert(engineOutPath != null); assert(androidBuildInfo != null); final String abi = _getAbiByLocalEnginePath(engineOutPath); - final Directory localEngineRepo = globals.fs.systemTempDirectory + final Directory localEngineRepo = fileSystem.systemTempDirectory .createTempSync('flutter_tool_local_engine_repo.'); // Remove the local engine repo before the tool exits. @@ -1137,19 +1149,20 @@ Directory _getLocalEngineRepo({ final String buildMode = androidBuildInfo.buildInfo.modeName; final String artifactVersion = _getLocalArtifactVersion( - globals.fs.path.join( + fileSystem.path.join( engineOutPath, 'flutter_embedding_$buildMode.pom', - ) + ), + fileSystem, ); for (final String artifact in const ['pom', 'jar']) { // The Android embedding artifacts. _createSymlink( - globals.fs.path.join( + fileSystem.path.join( engineOutPath, 'flutter_embedding_$buildMode.$artifact', ), - globals.fs.path.join( + fileSystem.path.join( localEngineRepo.path, 'io', 'flutter', @@ -1157,14 +1170,15 @@ Directory _getLocalEngineRepo({ artifactVersion, 'flutter_embedding_$buildMode-$artifactVersion.$artifact', ), + fileSystem, ); // The engine artifacts (libflutter.so). _createSymlink( - globals.fs.path.join( + fileSystem.path.join( engineOutPath, '${abi}_$buildMode.$artifact', ), - globals.fs.path.join( + fileSystem.path.join( localEngineRepo.path, 'io', 'flutter', @@ -1172,21 +1186,23 @@ Directory _getLocalEngineRepo({ artifactVersion, '${abi}_$buildMode-$artifactVersion.$artifact', ), + fileSystem, ); } for (final String artifact in ['flutter_embedding_$buildMode', '${abi}_$buildMode']) { _createSymlink( - globals.fs.path.join( + fileSystem.path.join( engineOutPath, '$artifact.maven-metadata.xml', ), - globals.fs.path.join( + fileSystem.path.join( localEngineRepo.path, 'io', 'flutter', artifact, 'maven-metadata.xml', ), + fileSystem, ); } return localEngineRepo; diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart index 7454e1f37a9..b239d8ba566 100644 --- a/packages/flutter_tools/lib/src/application_package.dart +++ b/packages/flutter_tools/lib/src/application_package.dart @@ -65,7 +65,7 @@ class ApplicationPackageFactory { case TargetPlatform.android_x64: case TargetPlatform.android_x86: if (_androidSdk?.licensesAvailable == true && _androidSdk?.latestVersion == null) { - await checkGradleDependencies(_logger); + await checkGradleDependencies(_logger, _processUtils); } if (applicationBinary == null) { return await AndroidApk.fromAndroidProject( diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index c798c3afa57..892e9ae735b 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -81,6 +81,8 @@ Future runInContext( fallbacks: { AndroidBuilder: () => AndroidGradleBuilder( logger: globals.logger, + processManager: globals.processManager, + fileSystem: globals.fs, ), AndroidLicenseValidator: () => AndroidLicenseValidator( operatingSystemUtils: globals.os, diff --git a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart index 362869c302c..e5f88d8e50c 100644 --- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart @@ -19,7 +19,6 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:mockito/mockito.dart'; @@ -27,7 +26,6 @@ import 'package:process/process.dart'; import '../../src/common.dart'; import '../../src/context.dart'; -import '../../src/mocks.dart'; void main() { group('gradle build', () { @@ -36,23 +34,25 @@ void main() { MockAndroidSdk mockAndroidSdk; MockAndroidStudio mockAndroidStudio; MockLocalEngineArtifacts mockArtifacts; - MockProcessManager mockProcessManager; FakePlatform android; FileSystem fileSystem; Cache cache; AndroidGradleBuilder builder; + FakeProcessManager processManager; setUp(() { + processManager = FakeProcessManager.list([]); logger = BufferLogger.test(); testUsage = TestUsage(); fileSystem = MemoryFileSystem.test(); mockAndroidSdk = MockAndroidSdk(); mockAndroidStudio = MockAndroidStudio(); mockArtifacts = MockLocalEngineArtifacts(); - mockProcessManager = MockProcessManager(); android = fakePlatform('android'); builder = AndroidGradleBuilder( logger: logger, + processManager: processManager, + fileSystem: fileSystem, ); when(mockAndroidSdk.directory).thenReturn(fileSystem.directory('irrelevant')); @@ -62,6 +62,7 @@ void main() { rootOverride: rootDirectory, fileSystem: fileSystem, ); + Cache.flutterRoot = ''; final Directory gradleWrapperDirectory = rootDirectory .childDirectory('bin') @@ -83,15 +84,21 @@ void main() { .writeAsStringSync('irrelevant'); }); - testUsingContext('recognizes common errors - tool exit', () async { - final Process process = createMockProcess( + testUsingContext('Can immediately tool exit on recognized exit code/stderr', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease' + ], exitCode: 1, - stdout: 'irrelevant\nSome gradle message\nirrelevant', - ); - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) => Future.value(process)); + stderr: '\nSome gradle message\n', + )); fileSystem.directory('android') .childFile('build.gradle') @@ -157,22 +164,40 @@ void main() { AndroidSdk: () => mockAndroidSdk, Cache: () => cache, Platform: () => android, - FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, Usage: () => testUsage, + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); - testUsingContext('recognizes common errors - retry build', () async { - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) { - final Process process = createMockProcess( - exitCode: 1, - stdout: 'irrelevant\nSome gradle message\nirrelevant', - ); - return Future.value(process); - }); + testUsingContext('Can retry build on recognized exit code/stderr', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 1, + stderr: '\nSome gradle message\n' + )); + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 1, + stderr: '\nSome gradle message\n' + )); fileSystem.directory('android') .childFile('build.gradle') @@ -239,16 +264,26 @@ void main() { AndroidSdk: () => mockAndroidSdk, Cache: () => cache, Platform: () => android, - FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, Usage: () => testUsage, + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); - testUsingContext('recognizes process exceptions - tool exit', () async { - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenThrow(const ProcessException('', [], 'Some gradle message')); + testUsingContext('Converts recognized ProcessExceptions into tools exits', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 1, + stderr: '\nSome gradle message\n', + )); fileSystem.directory('android') .childFile('build.gradle') @@ -314,16 +349,28 @@ void main() { AndroidSdk: () => mockAndroidSdk, Cache: () => cache, Platform: () => android, - FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, Usage: () => testUsage, + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('rethrows unrecognized ProcessException', () async { - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenThrow(const ProcessException('', [], 'Unrecognized')); + processManager.addCommand(FakeCommand( + command: const [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 1, + onRun: () { + throw const ProcessException('', [], 'Unrecognized'); + } + )); fileSystem.directory('android') .childFile('build.gradle') @@ -355,36 +402,43 @@ void main() { ); }, throwsA(isA())); - + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); testUsingContext('logs success event after a successful retry', () async { - int testFnCalled = 0; - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) { - Process process; - if (testFnCalled == 0) { - process = createMockProcess( - exitCode: 1, - stdout: 'irrelevant\nSome gradle message\nirrelevant', - ); - } else { - process = createMockProcess( - exitCode: 0, - stdout: 'irrelevant', - ); - } - testFnCalled++; - return Future.value(process); - }); + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 1, + stderr: '\nnSome gradle message\n', + )); + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 0, + )); fileSystem.directory('android') .childFile('build.gradle') @@ -435,7 +489,6 @@ void main() { ), ], ); - expect(testUsage.events, contains( const TestUsageEvent( 'build', @@ -444,25 +497,31 @@ void main() { parameters: {}, ), )); + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, Cache: () => cache, - FileSystem: () => fileSystem, Platform: () => android, - ProcessManager: () => mockProcessManager, Usage: () => testUsage, + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('performs code size analysis and sends analytics', () async { - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) { - return Future.value(createMockProcess( - exitCode: 0, - stdout: 'irrelevant', - )); - }); + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + '-Pcode-size-directory=foo', + 'assembleRelease', + ], + exitCode: 0, + )); fileSystem.directory('android') .childFile('build.gradle') @@ -533,23 +592,43 @@ void main() { }, overrides: { AndroidSdk: () => mockAndroidSdk, Cache: () => cache, - FileSystem: () => fileSystem, Platform: () => android, - ProcessManager: () => mockProcessManager, Usage: () => testUsage, + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); - testUsingContext('recognizes common errors - retry build with AAR plugins', () async { - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) { - final Process process = createMockProcess( - exitCode: 1, - stdout: 'irrelevant\nSome gradle message\nirrelevant', - ); - return Future.value(process); - }); + testUsingContext('Can retry gradle build with plugins built as AARs', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 1, + stderr: '\nSome gradle message\n', + )); + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + '-Dbuild-plugins-as-aars=true', + '--settings-file=settings_aar.gradle', + 'assembleRelease' + ], + exitCode: 1, + stderr: '\nSome gradle message\n', + )); fileSystem.directory('android') .childFile('build.gradle') @@ -618,16 +697,29 @@ void main() { parameters: {}, ), )); + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, Cache: () => cache, Platform: () => android, - FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, Usage: () => testUsage, + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('indicates that an APK has been built successfully', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease' + ], + )); fileSystem.directory('android') .childFile('build.gradle') .createSync(recursive: true); @@ -667,16 +759,34 @@ void main() { logger.statusText, contains('Built build/app/outputs/flutter-apk/app-release.apk (0.0MB)'), ); - + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, Cache: () => cache, - FileSystem: () => fileSystem, Platform: () => android, - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); - testUsingContext("doesn't indicate how to consume an AAR when printHowToConsumeAaar is false", () async { + testUsingContext("doesn't indicate how to consume an AAR when printHowToConsumeAar is false", () async { + processManager.addCommand(const FakeCommand( + command: [ + '/.android/gradlew', + '-I=/packages/flutter_tools/gradle/aar_init_script.gradle', + '-Pflutter-root=/', + '-Poutput-dir=build/', + '-Pis-plugin=false', + '-PbuildNumber=1.0', + '-q', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + 'assembleAarRelease', + ], + exitCode: 0, + )); + final File manifestFile = fileSystem.file('pubspec.yaml'); manifestFile.createSync(recursive: true); manifestFile.writeAsStringSync(''' @@ -694,13 +804,6 @@ void main() { fileSystem.file('.android/build.gradle') .createSync(recursive: true); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 0, '', '')); - fileSystem.directory('build/outputs/repo').createSync(recursive: true); await builder.buildGradleAar( @@ -719,17 +822,36 @@ void main() { logger.statusText.contains('Consuming the Module'), isFalse, ); - + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); - testUsingContext('gradle exit code is properly passed on', () async { + testUsingContext('gradle exit code and stderr is forwarded to tool exit', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/.android/gradlew', + '-I=/packages/flutter_tools/gradle/aar_init_script.gradle', + '-Pflutter-root=/', + '-Poutput-dir=build/', + '-Pis-plugin=false', + '-PbuildNumber=1.0', + '-q', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + '-Ptarget-platform=android-arm,android-arm64,android-x64', + 'assembleAarRelease' + ], + exitCode: 108, + stderr: 'Gradle task assembleAarRelease failed with exit code 108.', + )); + final File manifestFile = fileSystem.file('pubspec.yaml'); manifestFile.createSync(recursive: true); manifestFile.writeAsStringSync(''' @@ -747,13 +869,6 @@ void main() { fileSystem.file('.android/build.gradle') .createSync(recursive: true); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 108, '', '')); - fileSystem.directory('build/outputs/repo').createSync(recursive: true); await expectLater(() async => @@ -763,19 +878,35 @@ void main() { outputDirectory: fileSystem.directory('build/'), target: '', buildNumber: '1.0', - ) - , throwsToolExit(exitCode: 108, message: 'Gradle task assembleAarRelease failed with exit code 108.')); - + ), throwsToolExit(exitCode: 108, message: 'Gradle task assembleAarRelease failed with exit code 108.')); + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); - testUsingContext('build apk uses selected local engine,the engine abi is arm', () async { + testUsingContext('build apk uses selected local engine with arm32 ABI', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', + '-Plocal-engine-build-mode=release', + '-Plocal-engine-out=out/android_arm', + '-Ptarget-platform=android-arm', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 0, + )); + when(mockArtifacts.getArtifactPath( Artifact.flutterFramework, platform: TargetPlatform.android_arm, @@ -816,24 +947,6 @@ void main() { ..createSync(recursive: true) ..writeAsStringSync('apply from: irrelevant/flutter.gradle'); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 0, '', '')); - - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) { - return Future.value( - createMockProcess( - exitCode: 1, - ) - ); - }); - await expectLater(() async { await builder.buildGradleApp( project: FlutterProject.current(), @@ -850,18 +963,11 @@ void main() { ); }, throwsToolExit()); - final List actualGradlewCall = verify( - mockProcessManager.start( - captureAny, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory') - ), - ).captured.last as List; - expect(actualGradlewCall, contains('/android/gradlew')); - expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm')); - expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0')); - expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release')); + // expect(actualGradlewCall, contains('/android/gradlew')); + // expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm')); + // expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0')); + // expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release')); }, overrides: { AndroidSdk: () => mockAndroidSdk, @@ -870,11 +976,27 @@ void main() { Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); - testUsingContext( - 'build apk uses selected local engine,the engine abi is arm64', () async { + testUsingContext('build apk uses selected local engine with arm64 ABI', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', + '-Plocal-engine-build-mode=release', + '-Plocal-engine-out=out/android_arm64', + '-Ptarget-platform=android-arm64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 0, + )); + when(mockArtifacts.getArtifactPath( Artifact.flutterFramework, platform: anyNamed('platform'), @@ -915,24 +1037,6 @@ void main() { ..createSync(recursive: true) ..writeAsStringSync('apply from: irrelevant/flutter.gradle'); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 0, '', '')); - - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) { - return Future.value( - createMockProcess( - exitCode: 1, - ) - ); - }); - await expectLater(() async { await builder.buildGradleApp( project: FlutterProject.current(), @@ -948,20 +1052,7 @@ void main() { localGradleErrors: const [], ); }, throwsToolExit()); - - final List actualGradlewCall = verify( - mockProcessManager.start( - captureAny, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory') - ), - ).captured.last as List; - - expect(actualGradlewCall, contains('/android/gradlew')); - expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm64')); - expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0')); - expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release')); - + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, @@ -969,11 +1060,27 @@ void main() { Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); - testUsingContext( - 'build apk uses selected local engine,the engine abi is x86', () async { + testUsingContext('build apk uses selected local engine with x86 ABI', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', + '-Plocal-engine-build-mode=release', + '-Plocal-engine-out=out/android_x86', + '-Ptarget-platform=android-x86', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease', + ], + exitCode: 0, + )); + when(mockArtifacts.getArtifactPath( Artifact.flutterFramework, platform: anyNamed('platform'), @@ -1014,24 +1121,6 @@ void main() { ..createSync(recursive: true) ..writeAsStringSync('apply from: irrelevant/flutter.gradle'); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 0, '', '')); - - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) { - return Future.value( - createMockProcess( - exitCode: 1, - ) - ); - }); - await expectLater(() async { await builder.buildGradleApp( project: FlutterProject.current(), @@ -1047,20 +1136,7 @@ void main() { localGradleErrors: const [], ); }, throwsToolExit()); - - final List actualGradlewCall = verify( - mockProcessManager.start( - captureAny, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory') - ), - ).captured.last as List; - - expect(actualGradlewCall, contains('/android/gradlew')); - expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x86')); - expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0')); - expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release')); - + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, @@ -1068,11 +1144,27 @@ void main() { Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); - testUsingContext( - 'build apk uses selected local engine,the engine abi is x64', () async { + testUsingContext('build apk uses selected local engine with x64 ABI', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/android/gradlew', + '-q', + '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', + '-Plocal-engine-build-mode=release', + '-Plocal-engine-out=out/android_x64', + '-Ptarget-platform=android-x64', + '-Ptarget=lib/main.dart', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + 'assembleRelease' + ], + exitCode: 1, + )); + when(mockArtifacts.getArtifactPath( Artifact.flutterFramework, platform: anyNamed('platform'), @@ -1113,24 +1205,6 @@ void main() { ..createSync(recursive: true) ..writeAsStringSync('apply from: irrelevant/flutter.gradle'); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 0, '', '')); - - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) { - return Future.value( - createMockProcess( - exitCode: 1, - ) - ); - }); - await expectLater(() async { await builder.buildGradleApp( project: FlutterProject.current(), @@ -1146,20 +1220,7 @@ void main() { localGradleErrors: const [], ); }, throwsToolExit()); - - final List actualGradlewCall = verify( - mockProcessManager.start( - captureAny, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory') - ), - ).captured.last as List; - - expect(actualGradlewCall, contains('/android/gradlew')); - expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x64')); - expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0')); - expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release')); - + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, @@ -1167,11 +1228,11 @@ void main() { Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); testUsingContext('honors --no-android-gradle-daemon setting', () async { - (globals.processManager as FakeProcessManager).addCommand( + processManager.addCommand( const FakeCommand(command: [ '/android/gradlew', '-q', @@ -1215,6 +1276,7 @@ void main() { localGradleErrors: const [], ); }, throwsToolExit()); + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, @@ -1222,10 +1284,31 @@ void main() { Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list([]), + ProcessManager: () => processManager, }); - testUsingContext('build aar uses selected local engine,the engine abi is arm', () async { + testUsingContext('build aar uses selected local engine with arm32 ABI', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/.android/gradlew', + '-I=/packages/flutter_tools/gradle/aar_init_script.gradle', + '-Pflutter-root=/', + '-Poutput-dir=build/', + '-Pis-plugin=false', + '-PbuildNumber=2.0', + '-q', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', + '-Plocal-engine-build-mode=release', + '-Plocal-engine-out=out/android_arm', + '-Ptarget-platform=android-arm', + 'assembleAarRelease' + ], + exitCode: 0, + )); + when(mockArtifacts.getArtifactPath( Artifact.flutterFramework, platform: TargetPlatform.android_arm, @@ -1274,13 +1357,6 @@ void main() { fileSystem.file('.android/build.gradle') .createSync(recursive: true); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 0, '', '')); - fileSystem.directory('build/outputs/repo').createSync(recursive: true); await builder.buildGradleAar( @@ -1291,25 +1367,12 @@ void main() { buildNumber: '2.0', ); - final List actualGradlewCall = verify( - mockProcessManager.run( - captureAny, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - ), - ).captured.last as List; - - expect(actualGradlewCall, contains('/.android/gradlew')); - expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm')); - expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0')); - expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release')); - expect(actualGradlewCall, contains('-PbuildNumber=2.0')); - expect(fileSystem.link( 'build/outputs/repo/io/flutter/flutter_embedding_release/' '1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b/' 'flutter_embedding_release-1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b.pom' ), exists); + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, @@ -1317,11 +1380,31 @@ void main() { Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); - testUsingContext( - 'build aar uses selected local engine,the engine abi is arm64', () async { + testUsingContext('build aar uses selected local engine with x64 ABI', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/.android/gradlew', + '-I=/packages/flutter_tools/gradle/aar_init_script.gradle', + '-Pflutter-root=/', + '-Poutput-dir=build/', + '-Pis-plugin=false', + '-PbuildNumber=2.0', + '-q', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', + '-Plocal-engine-build-mode=release', + '-Plocal-engine-out=out/android_arm64', + '-Ptarget-platform=android-arm64', + 'assembleAarRelease' + ], + exitCode: 0, + )); + when(mockArtifacts.getArtifactPath( Artifact.flutterFramework, platform: anyNamed('platform'), @@ -1370,13 +1453,6 @@ void main() { fileSystem.file('.android/build.gradle') .createSync(recursive: true); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 0, '', '')); - fileSystem.directory('build/outputs/repo').createSync(recursive: true); await builder.buildGradleAar( @@ -1388,25 +1464,12 @@ void main() { buildNumber: '2.0', ); - final List actualGradlewCall = verify( - mockProcessManager.run( - captureAny, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - ), - ).captured.last as List; - - expect(actualGradlewCall, contains('/.android/gradlew')); - expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm64')); - expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0')); - expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release')); - expect(actualGradlewCall, contains('-PbuildNumber=2.0')); - expect(fileSystem.link( 'build/outputs/repo/io/flutter/flutter_embedding_release/' '1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b/' 'flutter_embedding_release-1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b.pom' ), exists); + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, @@ -1414,11 +1477,31 @@ void main() { Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); - testUsingContext( - 'build aar uses selected local engine,the engine abi is x86', () async { + testUsingContext('build aar uses selected local engine with x86 ABI', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/.android/gradlew', + '-I=/packages/flutter_tools/gradle/aar_init_script.gradle', + '-Pflutter-root=/', + '-Poutput-dir=build/', + '-Pis-plugin=false', + '-PbuildNumber=2.0', + '-q', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', + '-Plocal-engine-build-mode=release', + '-Plocal-engine-out=out/android_x86', + '-Ptarget-platform=android-x86', + 'assembleAarRelease' + ], + exitCode: 0, + )); + when(mockArtifacts.getArtifactPath( Artifact.flutterFramework, platform: anyNamed('platform'), @@ -1467,13 +1550,6 @@ void main() { fileSystem.file('.android/build.gradle') .createSync(recursive: true); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 0, '', '')); - fileSystem.directory('build/outputs/repo').createSync(recursive: true); await builder.buildGradleAar( @@ -1485,25 +1561,12 @@ void main() { buildNumber: '2.0', ); - final List actualGradlewCall = verify( - mockProcessManager.run( - captureAny, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - ), - ).captured.last as List; - - expect(actualGradlewCall, contains('/.android/gradlew')); - expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x86')); - expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0')); - expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release')); - expect(actualGradlewCall, contains('-PbuildNumber=2.0')); - expect(fileSystem.link( 'build/outputs/repo/io/flutter/flutter_embedding_release/' '1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b/' 'flutter_embedding_release-1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b.pom' ), exists); + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, @@ -1511,10 +1574,31 @@ void main() { Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); - testUsingContext('build aar uses selected local engine,the engine abi is x64', () async { + testUsingContext('build aar uses selected local engine on x64 ABI', () async { + processManager.addCommand(const FakeCommand( + command: [ + '/.android/gradlew', + '-I=/packages/flutter_tools/gradle/aar_init_script.gradle', + '-Pflutter-root=/', + '-Poutput-dir=build/', + '-Pis-plugin=false', + '-PbuildNumber=2.0', + '-q', + '-Pdart-obfuscation=false', + '-Ptrack-widget-creation=false', + '-Ptree-shake-icons=false', + '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', + '-Plocal-engine-build-mode=release', + '-Plocal-engine-out=out/android_x64', + '-Ptarget-platform=android-x64', + 'assembleAarRelease' + ], + exitCode: 0, + )); + when(mockArtifacts.getArtifactPath( Artifact.flutterFramework, platform: anyNamed('platform'), @@ -1563,13 +1647,6 @@ void main() { fileSystem.file('.android/build.gradle') .createSync(recursive: true); - // Let any process start. Assert after. - when(mockProcessManager.run( - any, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - )).thenAnswer((_) async => ProcessResult(1, 0, '', '')); - fileSystem.directory('build/outputs/repo').createSync(recursive: true); await builder.buildGradleAar( @@ -1581,25 +1658,12 @@ void main() { buildNumber: '2.0', ); - final List actualGradlewCall = verify( - mockProcessManager.run( - captureAny, - environment: anyNamed('environment'), - workingDirectory: anyNamed('workingDirectory'), - ), - ).captured.last as List; - - expect(actualGradlewCall, contains('/.android/gradlew')); - expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x64')); - expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0')); - expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release')); - expect(actualGradlewCall, contains('-PbuildNumber=2.0')); - expect(fileSystem.link( 'build/outputs/repo/io/flutter/flutter_embedding_release/' '1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b/' 'flutter_embedding_release-1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b.pom' ), exists); + expect(processManager.hasRemainingExpectations, false); }, overrides: { AndroidSdk: () => mockAndroidSdk, AndroidStudio: () => mockAndroidStudio, @@ -1607,7 +1671,7 @@ void main() { Cache: () => cache, Platform: () => android, FileSystem: () => fileSystem, - ProcessManager: () => mockProcessManager, + ProcessManager: () => processManager, }); }); } @@ -1620,7 +1684,6 @@ FakePlatform fakePlatform(String name) { ); } -class MockProcessManager extends Mock implements ProcessManager {} class MockAndroidSdk extends Mock implements AndroidSdk {} class MockAndroidStudio extends Mock implements AndroidStudio {} class MockLocalEngineArtifacts extends Mock implements LocalEngineArtifacts {} diff --git a/packages/flutter_tools/test/general.shard/android/gradle_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_test.dart index 8ec723aaf2b..cc608f308be 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_test.dart @@ -436,9 +436,11 @@ void main() { group('Config files', () { Directory tempDir; + FileSystem fileSystem; setUp(() { - tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_settings_aar_test.'); + fileSystem = MemoryFileSystem.test(); + tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_settings_aar_test.'); }); testUsingContext('create settings_aar.gradle when current settings.gradle loads plugins', () { @@ -468,25 +470,24 @@ include ':app' tempDir.childFile('settings.gradle').writeAsStringSync(currentSettingsGradle); - final String toolGradlePath = globals.fs.path.join( - globals.fs.path.absolute(Cache.flutterRoot), + final String toolGradlePath = fileSystem.path.join( + fileSystem.path.absolute(Cache.flutterRoot), 'packages', 'flutter_tools', 'gradle'); - globals.fs.directory(toolGradlePath).createSync(recursive: true); - globals.fs.file(globals.fs.path.join(toolGradlePath, 'settings.gradle.legacy_versions')) + fileSystem.directory(toolGradlePath).createSync(recursive: true); + fileSystem.file(fileSystem.path.join(toolGradlePath, 'settings.gradle.legacy_versions')) .writeAsStringSync(currentSettingsGradle); - globals.fs.file(globals.fs.path.join(toolGradlePath, 'settings_aar.gradle.tmpl')) + fileSystem.file(fileSystem.path.join(toolGradlePath, 'settings_aar.gradle.tmpl')) .writeAsStringSync(settingsAarFile); createSettingsAarGradle(tempDir, testLogger); expect(testLogger.statusText, contains('created successfully')); expect(tempDir.childFile('settings_aar.gradle').existsSync(), isTrue); - }, overrides: { - FileSystem: () => MemoryFileSystem.test(), + FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.any(), }); @@ -501,25 +502,24 @@ include ':app' tempDir.childFile('settings.gradle').writeAsStringSync(currentSettingsGradle); - final String toolGradlePath = globals.fs.path.join( - globals.fs.path.absolute(Cache.flutterRoot), + final String toolGradlePath = fileSystem.path.join( + fileSystem.path.absolute(Cache.flutterRoot), 'packages', 'flutter_tools', 'gradle'); - globals.fs.directory(toolGradlePath).createSync(recursive: true); - globals.fs.file(globals.fs.path.join(toolGradlePath, 'settings.gradle.legacy_versions')) + fileSystem.directory(toolGradlePath).createSync(recursive: true); + fileSystem.file(fileSystem.path.join(toolGradlePath, 'settings.gradle.legacy_versions')) .writeAsStringSync(currentSettingsGradle); - globals.fs.file(globals.fs.path.join(toolGradlePath, 'settings_aar.gradle.tmpl')) + fileSystem.file(fileSystem.path.join(toolGradlePath, 'settings_aar.gradle.tmpl')) .writeAsStringSync(settingsAarFile); createSettingsAarGradle(tempDir, testLogger); expect(testLogger.statusText, contains('created successfully')); expect(tempDir.childFile('settings_aar.gradle').existsSync(), isTrue); - }, overrides: { - FileSystem: () => MemoryFileSystem.test(), + FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.any(), }); }); @@ -860,7 +860,7 @@ flutter: fakeProcessManager = FakeProcessManager.list([]); mockAndroidSdk = MockAndroidSdk(); when(mockAndroidSdk.directory).thenReturn(fs.directory('irrelevant')); - builder = AndroidGradleBuilder(logger: logger); + builder = AndroidGradleBuilder(logger: logger, processManager: fakeProcessManager, fileSystem: fs); }); testUsingContext('calls gradle', () async {