diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart index 02884c7c6d..ac64e1c398 100644 --- a/packages/flutter_tools/lib/src/android/gradle.dart +++ b/packages/flutter_tools/lib/src/android/gradle.dart @@ -22,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, processManager, processUtils, fs, artifacts; +import '../globals.dart' as globals hide logger, printStatus, printTrace, printError, processManager, processUtils, fs, artifacts, flutterUsage; import '../project.dart'; import '../reporting/reporting.dart'; import 'android_builder.dart'; @@ -129,14 +129,6 @@ bool _isSupportedVersion(AndroidProject project) { return false; } -/// Returns the apk file created by [buildGradleProject] -Future getGradleAppOut(AndroidProject androidProject) async { - if (!_isSupportedVersion(androidProject)) { - _exitWithUnsupportedProjectMessage(); - } - return getApkDirectory(androidProject.parent).childFile('app.apk'); -} - /// Runs `gradlew dependencies`, ensuring that dependencies are resolved and /// potentially downloaded. Future checkGradleDependencies(Logger logger, ProcessUtils processUtils) async { @@ -217,15 +209,18 @@ class AndroidGradleBuilder implements AndroidBuilder { @required ProcessManager processManager, @required FileSystem fileSystem, @required Artifacts artifacts, + @required Usage usage, }) : _logger = logger, _fileSystem = fileSystem, _artifacts = artifacts, + _usage = usage, _processUtils = ProcessUtils(logger: logger, processManager: processManager); final Logger _logger; final ProcessUtils _processUtils; final FileSystem _fileSystem; final Artifacts _artifacts; + final Usage _usage; /// Builds the AAR and POM files for the current Flutter module or plugin. @override @@ -336,18 +331,18 @@ class AndroidGradleBuilder implements AndroidBuilder { assert(globals.androidSdk != null); if (!project.android.isUsingGradle) { - _exitWithProjectNotUsingGradleMessage(); + _exitWithProjectNotUsingGradleMessage(_usage); } if (!_isSupportedVersion(project.android)) { - _exitWithUnsupportedProjectMessage(); + _exitWithUnsupportedProjectMessage(_usage); } final Directory buildDirectory = project.android.buildDirectory; final bool usesAndroidX = isAppUsingAndroidX(project.android.hostAppGradleRoot); if (usesAndroidX) { - BuildEvent('app-using-android-x', flutterUsage: globals.flutterUsage).send(); + BuildEvent('app-using-android-x', flutterUsage: _usage).send(); } else if (!usesAndroidX) { - BuildEvent('app-not-using-android-x', flutterUsage: globals.flutterUsage).send(); + BuildEvent('app-not-using-android-x', flutterUsage: _usage).send(); _logger.printStatus("$warningMark Your app isn't using AndroidX.", emphasis: true); _logger.printStatus( 'To avoid potential build failures, you can quickly migrate your app ' @@ -488,11 +483,11 @@ class AndroidGradleBuilder implements AndroidBuilder { status.stop(); } - globals.flutterUsage.sendTiming('build', 'gradle', sw.elapsed); + _usage.sendTiming('build', 'gradle', sw.elapsed); if (exitCode != 0) { if (detectedGradleError == null) { - BuildEvent('gradle-unknown-failure', flutterUsage: globals.flutterUsage).send(); + BuildEvent('gradle-unknown-failure', flutterUsage: _usage).send(); throwToolExit( 'Gradle task $assembleTask failed with exit code $exitCode', exitCode: exitCode, @@ -518,7 +513,7 @@ class AndroidGradleBuilder implements AndroidBuilder { shouldBuildPluginAsAar: shouldBuildPluginAsAar, retries: retries - 1, ); - BuildEvent(successEventLabel, flutterUsage: globals.flutterUsage).send(); + BuildEvent(successEventLabel, flutterUsage: _usage).send(); return; case GradleBuildStatus.retryWithAarPlugins: await buildGradleApp( @@ -530,13 +525,13 @@ class AndroidGradleBuilder implements AndroidBuilder { shouldBuildPluginAsAar: true, retries: retries - 1, ); - BuildEvent(successEventLabel, flutterUsage: globals.flutterUsage).send(); + BuildEvent(successEventLabel, flutterUsage: _usage).send(); return; case GradleBuildStatus.exit: // noop. } } - BuildEvent('gradle-${detectedGradleError.eventLabel}-failure', flutterUsage: globals.flutterUsage).send(); + BuildEvent('gradle-${detectedGradleError.eventLabel}-failure', flutterUsage: _usage).send(); throwToolExit( 'Gradle task $assembleTask failed with exit code $exitCode', exitCode: exitCode, @@ -545,7 +540,7 @@ class AndroidGradleBuilder implements AndroidBuilder { } if (isBuildingBundle) { - final File bundleFile = findBundleFile(project, buildInfo, _logger); + final File bundleFile = findBundleFile(project, buildInfo, _logger, _usage); final String appSize = (buildInfo.mode == BuildMode.debug) ? '' // Don't display the size when building a debug variant. : ' (${getSizeAsMB(bundleFile.lengthSync())})'; @@ -562,7 +557,7 @@ class AndroidGradleBuilder implements AndroidBuilder { } // Gradle produced an APK. final Iterable apkFilesPaths = project.isModule - ? findApkFilesModule(project, androidBuildInfo, _logger) + ? findApkFilesModule(project, androidBuildInfo, _logger, _usage) : listApkPaths(androidBuildInfo); final Directory apkDirectory = getApkDirectory(project); final File apkFile = apkDirectory.childFile(apkFilesPaths.first); @@ -571,6 +566,7 @@ class AndroidGradleBuilder implements AndroidBuilder { project: project, fileExtension: '.apk', logger: _logger, + usage: _usage, ); } @@ -603,7 +599,7 @@ class AndroidGradleBuilder implements AndroidBuilder { final SizeAnalyzer sizeAnalyzer = SizeAnalyzer( fileSystem: _fileSystem, logger: _logger, - flutterUsage: globals.flutterUsage, + flutterUsage: _usage, ); final String archName = getNameForAndroidArch(androidBuildInfo.targetArchs.single); final BuildInfo buildInfo = androidBuildInfo.buildInfo; @@ -760,7 +756,7 @@ class AndroidGradleBuilder implements AndroidBuilder { } finally { status.stop(); } - globals.flutterUsage.sendTiming('build', 'gradle-aar', sw.elapsed); + _usage.sendTiming('build', 'gradle-aar', sw.elapsed); if (result.exitCode != 0) { _logger.printStatus(result.stdout, wrap: false); @@ -830,12 +826,11 @@ class AndroidGradleBuilder implements AndroidBuilder { } on ToolExit { // Log the entire plugin entry in `.flutter-plugins` since it // includes the plugin name and the version. - BuildEvent('gradle-plugin-aar-failure', eventError: plugin, flutterUsage: globals.flutterUsage).send(); + BuildEvent('gradle-plugin-aar-failure', eventError: plugin, flutterUsage: _usage).send(); throwToolExit('The plugin $pluginName could not be built due to the issue above.'); } } } - } /// Prints how to consume the AAR from a host app. @@ -911,8 +906,8 @@ String _calculateSha(File file) { return _hex(sha1.convert(bytes).bytes); } -void _exitWithUnsupportedProjectMessage() { - BuildEvent('unsupported-project', eventError: 'gradle-plugin', flutterUsage: globals.flutterUsage).send(); +void _exitWithUnsupportedProjectMessage(Usage usage) { + BuildEvent('unsupported-project', eventError: 'gradle-plugin', flutterUsage: usage).send(); throwToolExit( '$warningMark Your app is using an unsupported Gradle project. ' 'To fix this problem, create a new project by running `flutter create -t app ` ' @@ -920,8 +915,8 @@ void _exitWithUnsupportedProjectMessage() { ); } -void _exitWithProjectNotUsingGradleMessage() { - BuildEvent('unsupported-project', eventError: 'app-not-using-gradle', flutterUsage: globals.flutterUsage).send(); +void _exitWithProjectNotUsingGradleMessage(Usage usage) { + BuildEvent('unsupported-project', eventError: 'app-not-using-gradle', flutterUsage: usage).send(); throwToolExit( '$warningMark The build process for Android has changed, and the ' 'current project configuration is no longer valid. Please consult\n\n' @@ -930,6 +925,14 @@ void _exitWithProjectNotUsingGradleMessage() { ); } +/// Returns the apk file created by [buildGradleProject] +Future getGradleAppOut(AndroidProject androidProject, Usage usage) async { + if (!_isSupportedVersion(androidProject)) { + _exitWithUnsupportedProjectMessage(usage); + } + return getApkDirectory(androidProject.parent).childFile('app.apk'); +} + /// Returns [true] if the current app uses AndroidX. // TODO(egarciad): https://github.com/flutter/flutter/issues/40800 // Remove `FlutterManifest.usesAndroidX` and provide a unified `AndroidProject.usesAndroidX`. @@ -947,6 +950,7 @@ Iterable findApkFilesModule( FlutterProject project, AndroidBuildInfo androidBuildInfo, Logger logger, + Usage usage, ) { final Iterable apkFileNames = _apkFilesFor(androidBuildInfo); final Directory apkDirectory = getApkDirectory(project); @@ -980,6 +984,7 @@ Iterable findApkFilesModule( project: project, fileExtension: '.apk', logger: logger, + usage: usage, ); } return apks.map((File file) => file.path); @@ -1018,7 +1023,7 @@ Iterable listApkPaths( } @visibleForTesting -File findBundleFile(FlutterProject project, BuildInfo buildInfo, Logger logger) { +File findBundleFile(FlutterProject project, BuildInfo buildInfo, Logger logger, Usage usage) { final List fileCandidates = [ getBundleDirectory(project) .childDirectory(camelCase(buildInfo.modeName)) @@ -1053,6 +1058,7 @@ File findBundleFile(FlutterProject project, BuildInfo buildInfo, Logger logger) project: project, fileExtension: '.aab', logger: logger, + usage: usage, ); return null; } @@ -1062,6 +1068,7 @@ void _exitWithExpectedFileNotFound({ @required FlutterProject project, @required String fileExtension, @required Logger logger, + @required Usage usage, }) { assert(project != null); assert(fileExtension != null); @@ -1072,7 +1079,7 @@ void _exitWithExpectedFileNotFound({ settings: 'androidGradlePluginVersion: $androidGradlePluginVersion, ' 'fileExtension: $fileExtension', - flutterUsage: globals.flutterUsage, + flutterUsage: usage, ).send(); throwToolExit( 'Gradle build failed to produce an $fileExtension file. ' diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart index b239d8ba56..269df04e8a 100644 --- a/packages/flutter_tools/lib/src/application_package.dart +++ b/packages/flutter_tools/lib/src/application_package.dart @@ -221,7 +221,7 @@ class AndroidApk extends ApplicationPackage { File apkFile; if (androidProject.isUsingGradle) { - apkFile = await getGradleAppOut(androidProject); + apkFile = await getGradleAppOut(androidProject, globals.flutterUsage); if (apkFile.existsSync()) { // Grab information from the .apk. The gradle build script might alter // the application Id, so we need to look at what was actually built. diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index a662d6f57f..4cb7e6fd8f 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -84,6 +84,7 @@ Future runInContext( processManager: globals.processManager, fileSystem: globals.fs, artifacts: globals.artifacts, + usage: globals.flutterUsage, ), 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 0bebfea67f..8874a77de5 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 @@ -81,6 +81,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -172,6 +173,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -278,6 +280,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -369,6 +372,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(FakeCommand( command: const [ @@ -432,6 +436,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -534,6 +539,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -631,6 +637,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -746,6 +753,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -813,6 +821,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -880,6 +889,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -940,6 +950,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(localEngine: 'out/android_arm'), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -1018,6 +1029,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(localEngine: 'out/android_arm64'), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -1096,6 +1108,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(localEngine: 'out/android_x86'), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -1174,6 +1187,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(localEngine: 'out/android_x64'), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -1252,6 +1266,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(), + usage: testUsage, ); processManager.addCommand( const FakeCommand(command: [ @@ -1311,6 +1326,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(localEngine: 'out/android_arm'), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -1400,6 +1416,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(localEngine: 'out/android_arm64'), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -1489,6 +1506,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(localEngine: 'out/android_x86'), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ @@ -1578,6 +1596,7 @@ void main() { processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.test(localEngine: 'out/android_x64'), + usage: testUsage, ); processManager.addCommand(const FakeCommand( command: [ diff --git a/packages/flutter_tools/test/general.shard/android/gradle_find_bundle_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_find_bundle_test.dart new file mode 100644 index 0000000000..1d93daea8d --- /dev/null +++ b/packages/flutter_tools/test/general.shard/android/gradle_find_bundle_test.dart @@ -0,0 +1,366 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// @dart = 2.8 + +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/android/gradle.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/project.dart'; +import 'package:flutter_tools/src/reporting/reporting.dart'; +import 'package:mockito/mockito.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; + +void main() { + FileSystem fileSystem; + + setUp(() { + fileSystem = MemoryFileSystem.test(); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores in release mode', () { + final FlutterProject project = generateFakeAppBundle('foo_barRelease', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.release, 'foo_bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barRelease', 'app.aab')); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in release mode', () { + final FlutterProject project = generateFakeAppBundle('foo_barRelease', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.release, 'foo_Bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barRelease', 'app.aab')); + }); + + testWithoutContext("Finds app bundle when flavor doesn't contain underscores in release mode", () { + final FlutterProject project = generateFakeAppBundle('fooRelease', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.release, 'foo', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooRelease', 'app.aab')); + }); + + testWithoutContext("Finds app bundle when flavor doesn't contain underscores but contains uppercase letters in release mode", () { + final FlutterProject project = generateFakeAppBundle('fooaRelease', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.release, 'fooA', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooaRelease', 'app.aab')); + }); + + testWithoutContext('Finds app bundle when no flavor is used in release mode', () { + final FlutterProject project = generateFakeAppBundle('release', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.release, null, treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'release', 'app.aab')); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores in debug mode', () { + final FlutterProject project = generateFakeAppBundle('foo_barDebug', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.debug, 'foo_bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barDebug', 'app.aab')); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in debug mode', () { + final FlutterProject project = generateFakeAppBundle('foo_barDebug', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.debug, 'foo_Bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barDebug', 'app.aab')); + }); + + testWithoutContext("Finds app bundle when flavor doesn't contain underscores in debug mode", () { + final FlutterProject project = generateFakeAppBundle('fooDebug', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.debug, 'foo', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooDebug', 'app.aab')); + }); + + testWithoutContext("Finds app bundle when flavor doesn't contain underscores but contains uppercase letters in debug mode", () { + final FlutterProject project = generateFakeAppBundle('fooaDebug', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.debug, 'fooA', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooaDebug', 'app.aab')); + }); + + testWithoutContext('Finds app bundle when no flavor is used in debug mode', () { + final FlutterProject project = generateFakeAppBundle('debug', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + BuildInfo.debug, + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'debug', 'app.aab')); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores in profile mode', () { + final FlutterProject project = generateFakeAppBundle('foo_barProfile', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.profile, 'foo_bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barProfile', 'app.aab')); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in profile mode', () { + final FlutterProject project = generateFakeAppBundle('foo_barProfile', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.profile, 'foo_Bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barProfile', 'app.aab')); + }); + + testWithoutContext("Finds app bundle when flavor doesn't contain underscores in profile mode", () { + final FlutterProject project = generateFakeAppBundle('fooProfile', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.profile, 'foo', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooProfile', 'app.aab')); + }); + + testWithoutContext("Finds app bundle when flavor doesn't contain underscores but contains uppercase letters in profile mode", () { + final FlutterProject project = generateFakeAppBundle('fooaProfile', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.profile, 'fooA', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooaProfile', 'app.aab')); + }); + + testWithoutContext('Finds app bundle when no flavor is used in profile mode', () { + final FlutterProject project = generateFakeAppBundle('profile', 'app.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.profile, null, treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'profile', 'app.aab')); + }); + + testWithoutContext('Finds app bundle in release mode - Gradle 3.5', () { + final FlutterProject project = generateFakeAppBundle('release', 'app-release.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.release, null, treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'release', 'app-release.aab')); + }); + + testWithoutContext('Finds app bundle in profile mode - Gradle 3.5', () { + final FlutterProject project = generateFakeAppBundle('profile', 'app-profile.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.profile, null, treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'profile', 'app-profile.aab')); + }); + + testWithoutContext('Finds app bundle in debug mode - Gradle 3.5', () { + final FlutterProject project = generateFakeAppBundle('debug', 'app-debug.aab', fileSystem); + final File bundle = findBundleFile( + project, + BuildInfo.debug, + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'debug', 'app-debug.aab')); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores in release mode - Gradle 3.5', () { + final FlutterProject project = generateFakeAppBundle('foo_barRelease', 'app-foo_bar-release.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.release, 'foo_bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barRelease', 'app-foo_bar-release.aab')); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in release mode - Gradle 3.5', () { + final FlutterProject project = generateFakeAppBundle('foo_barRelease', 'app-foo_bar-release.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.release, 'foo_Bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barRelease', 'app-foo_bar-release.aab')); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores in profile mode - Gradle 3.5', () { + final FlutterProject project = generateFakeAppBundle('foo_barProfile', 'app-foo_bar-profile.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.profile, 'foo_bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barProfile', 'app-foo_bar-profile.aab')); + }); + + testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in debug mode - Gradle 3.5', () { + final FlutterProject project = generateFakeAppBundle('foo_barDebug', 'app-foo_bar-debug.aab', fileSystem); + final File bundle = findBundleFile( + project, + const BuildInfo(BuildMode.debug, 'foo_Bar', treeShakeIcons: false), + BufferLogger.test(), + TestUsage(), + ); + + expect(bundle, isNotNull); + expect(bundle.path, fileSystem.path.join('irrelevant','app', 'outputs', 'bundle', 'foo_barDebug', 'app-foo_bar-debug.aab')); + }); + + // Context is required due to build failure analytics event grabbing FlutterCommand.current. + testUsingContext('AAB not found', () { + final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); + final TestUsage testUsage = TestUsage(); + expect( + () { + findBundleFile( + project, + const BuildInfo(BuildMode.debug, 'foo_bar', treeShakeIcons: false), + BufferLogger.test(), + testUsage, + ); + }, + throwsToolExit( + message: + "Gradle build failed to produce an .aab file. It's likely that this file " + "was generated under ${project.android.buildDirectory.path}, but the tool couldn't find it." + ) + ); + expect(testUsage.events, contains( + const TestUsageEvent( + 'build', + 'unspecified', + label: 'gradle-expected-file-not-found', + parameters: { + 'cd37': 'androidGradlePluginVersion: 6.7, fileExtension: .aab', + }, + ), + )); + }); +} + +/// Generates a fake app bundle at the location [directoryName]/[fileName]. +FlutterProject generateFakeAppBundle(String directoryName, String fileName, FileSystem fileSystem) { + final FlutterProject project = MockFlutterProject(); + final AndroidProject androidProject = MockAndroidProject(); + + when(project.isModule).thenReturn(false); + when(project.android).thenReturn(androidProject); + when(androidProject.buildDirectory).thenReturn(fileSystem.directory('irrelevant')); + + final Directory bundleDirectory = getBundleDirectory(project); + bundleDirectory + .childDirectory(directoryName) + .createSync(recursive: true); + + bundleDirectory + .childDirectory(directoryName) + .childFile(fileName) + .createSync(); + return project; +} + +class MockAndroidProject extends Mock implements AndroidProject {} +class MockFlutterProject extends Mock implements FlutterProject {} 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 c388165bc7..33d3a6e6ec 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_test.dart @@ -132,216 +132,6 @@ void main() { }); }); - group('findBundleFile', () { - FileSystem fileSystem; - TestUsage testUsage; - - setUp(() { - fileSystem = MemoryFileSystem.test(); - testUsage = TestUsage(); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores in release mode', () { - final FlutterProject project = generateFakeAppBundle('foo_barRelease', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.release, 'foo_bar', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barRelease', 'app.aab')); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in release mode', () { - final FlutterProject project = generateFakeAppBundle('foo_barRelease', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.release, 'foo_Bar', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barRelease', 'app.aab')); - }); - - testWithoutContext("Finds app bundle when flavor doesn't contain underscores in release mode", () { - final FlutterProject project = generateFakeAppBundle('fooRelease', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.release, 'foo', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooRelease', 'app.aab')); - }); - - testWithoutContext("Finds app bundle when flavor doesn't contain underscores but contains uppercase letters in release mode", () { - final FlutterProject project = generateFakeAppBundle('fooaRelease', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.release, 'fooA', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooaRelease', 'app.aab')); - }); - - testWithoutContext('Finds app bundle when no flavor is used in release mode', () { - final FlutterProject project = generateFakeAppBundle('release', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.release, null, treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'release', 'app.aab')); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores in debug mode', () { - final FlutterProject project = generateFakeAppBundle('foo_barDebug', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.debug, 'foo_bar', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barDebug', 'app.aab')); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in debug mode', () { - final FlutterProject project = generateFakeAppBundle('foo_barDebug', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.debug, 'foo_Bar', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barDebug', 'app.aab')); - }); - - testWithoutContext("Finds app bundle when flavor doesn't contain underscores in debug mode", () { - final FlutterProject project = generateFakeAppBundle('fooDebug', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.debug, 'foo', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooDebug', 'app.aab')); - }); - - testWithoutContext("Finds app bundle when flavor doesn't contain underscores but contains uppercase letters in debug mode", () { - final FlutterProject project = generateFakeAppBundle('fooaDebug', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.debug, 'fooA', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooaDebug', 'app.aab')); - }); - - testWithoutContext('Finds app bundle when no flavor is used in debug mode', () { - final FlutterProject project = generateFakeAppBundle('debug', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, BuildInfo.debug, BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'debug', 'app.aab')); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores in profile mode', () { - final FlutterProject project = generateFakeAppBundle('foo_barProfile', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.profile, 'foo_bar', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barProfile', 'app.aab')); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in profile mode', () { - final FlutterProject project = generateFakeAppBundle('foo_barProfile', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.profile, 'foo_Bar', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barProfile', 'app.aab')); - }); - - testWithoutContext("Finds app bundle when flavor doesn't contain underscores in profile mode", () { - final FlutterProject project = generateFakeAppBundle('fooProfile', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.profile, 'foo', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooProfile', 'app.aab')); - }); - - testWithoutContext("Finds app bundle when flavor doesn't contain underscores but contains uppercase letters in profile mode", () { - final FlutterProject project = generateFakeAppBundle('fooaProfile', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.profile, 'fooA', treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'fooaProfile', 'app.aab')); - }); - - testWithoutContext('Finds app bundle when no flavor is used in profile mode', () { - final FlutterProject project = generateFakeAppBundle('profile', 'app.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.profile, null, treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'profile', 'app.aab')); - }); - - testWithoutContext('Finds app bundle in release mode - Gradle 3.5', () { - final FlutterProject project = generateFakeAppBundle('release', 'app-release.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.release, null, treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'release', 'app-release.aab')); - }); - - testWithoutContext('Finds app bundle in profile mode - Gradle 3.5', () { - final FlutterProject project = generateFakeAppBundle('profile', 'app-profile.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.profile, null, treeShakeIcons: false), BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'profile', 'app-profile.aab')); - }); - - testWithoutContext('Finds app bundle in debug mode - Gradle 3.5', () { - final FlutterProject project = generateFakeAppBundle('debug', 'app-debug.aab', fileSystem); - final File bundle = findBundleFile(project, BuildInfo.debug, BufferLogger.test()); - - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'debug', 'app-debug.aab')); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores in release mode - Gradle 3.5', () { - final FlutterProject project = generateFakeAppBundle('foo_barRelease', 'app-foo_bar-release.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.release, 'foo_bar', treeShakeIcons: false), BufferLogger.test()); - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barRelease', 'app-foo_bar-release.aab')); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in release mode - Gradle 3.5', () { - final FlutterProject project = generateFakeAppBundle('foo_barRelease', 'app-foo_bar-release.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.release, 'foo_Bar', treeShakeIcons: false), BufferLogger.test()); - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barRelease', 'app-foo_bar-release.aab')); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores in profile mode - Gradle 3.5', () { - final FlutterProject project = generateFakeAppBundle('foo_barProfile', 'app-foo_bar-profile.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.profile, 'foo_bar', treeShakeIcons: false), BufferLogger.test()); - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant', 'app', 'outputs', 'bundle', 'foo_barProfile', 'app-foo_bar-profile.aab')); - }); - - testWithoutContext('Finds app bundle when flavor contains underscores and uppercase letters in debug mode - Gradle 3.5', () { - final FlutterProject project = generateFakeAppBundle('foo_barDebug', 'app-foo_bar-debug.aab', fileSystem); - final File bundle = findBundleFile(project, const BuildInfo(BuildMode.debug, 'foo_Bar', treeShakeIcons: false), BufferLogger.test()); - expect(bundle, isNotNull); - expect(bundle.path, fileSystem.path.join('irrelevant','app', 'outputs', 'bundle', 'foo_barDebug', 'app-foo_bar-debug.aab')); - }); - - testUsingContext('aab not found', () { - final FlutterProject project = FlutterProject.fromDirectoryTest(globals.fs.currentDirectory); - expect( - () { - findBundleFile(project, const BuildInfo(BuildMode.debug, 'foo_bar', treeShakeIcons: false), BufferLogger.test()); - }, - throwsToolExit( - message: - "Gradle build failed to produce an .aab file. It's likely that this file " - "was generated under ${project.android.buildDirectory.path}, but the tool couldn't find it." - ) - ); - expect(testUsage.events, contains( - const TestUsageEvent( - 'build', - 'unspecified', - label: 'gradle-expected-file-not-found', - parameters: { - 'cd37': 'androidGradlePluginVersion: 6.7, fileExtension: .aab', - }, - ), - )); - }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), - Usage: () => testUsage, - }); - }); - group('listApkPaths', () { testWithoutContext('Finds APK without flavor in release', () { final Iterable apks = listApkPaths( @@ -865,6 +655,7 @@ flutter: processManager: fakeProcessManager, fileSystem: fs, artifacts: Artifacts.test(), + usage: TestUsage(), ); }); @@ -1233,27 +1024,6 @@ plugin1=${plugin1.path} }, skip: true); // TODO(jonahwilliams): This is an integration test and should be moved to the integration shard. } -/// Generates a fake app bundle at the location [directoryName]/[fileName]. -FlutterProject generateFakeAppBundle(String directoryName, String fileName, FileSystem fileSystem) { - final FlutterProject project = MockFlutterProject(); - final AndroidProject androidProject = MockAndroidProject(); - - when(project.isModule).thenReturn(false); - when(project.android).thenReturn(androidProject); - when(androidProject.buildDirectory).thenReturn(fileSystem.directory('irrelevant')); - - final Directory bundleDirectory = getBundleDirectory(project); - bundleDirectory - .childDirectory(directoryName) - .createSync(recursive: true); - - bundleDirectory - .childDirectory(directoryName) - .childFile(fileName) - .createSync(); - return project; -} - FakePlatform fakePlatform(String name) { return FakePlatform( environment: {'HOME': '/path/to/home'},