build_appbundle_test.dart 7.71 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:args/command_runner.dart';
import 'package:flutter_tools/src/android/android_builder.dart';
7
import 'package:flutter_tools/src/android/android_sdk.dart';
8 9 10
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build_appbundle.dart';
11
import 'package:flutter_tools/src/globals.dart' as globals;
12
import 'package:flutter_tools/src/project.dart';
13
import 'package:flutter_tools/src/reporting/reporting.dart';
14
import 'package:test/fake.dart';
15

16
import '../../src/android_common.dart';
17 18
import '../../src/common.dart';
import '../../src/context.dart';
19
import '../../src/test_flutter_command_runner.dart';
20 21 22 23

void main() {
  Cache.disableLocking();

24
  group('Usage', () {
25 26
    late Directory tempDir;
    late TestUsage testUsage;
27 28

    setUp(() {
29
      tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
30
      testUsage = TestUsage();
31 32 33 34 35 36 37 38 39
    });

    tearDown(() {
      tryToDelete(tempDir);
    });

    testUsingContext('indicate the default target platforms', () async {
      final String projectPath = await createProject(tempDir,
          arguments: <String>['--no-pub', '--template=app']);
40
      final BuildAppBundleCommand command = await runBuildAppBundleCommand(projectPath);
41

42
      expect((await command.usageValues).commandBuildAppBundleTargetPlatform, 'android-arm,android-arm64,android-x64');
43 44 45

    }, overrides: <Type, Generator>{
      AndroidBuilder: () => FakeAndroidBuilder(),
46
    });
47 48 49 50 51

    testUsingContext('build type', () async {
      final String projectPath = await createProject(tempDir,
          arguments: <String>['--no-pub', '--template=app']);

52
      final BuildAppBundleCommand commandDefault = await runBuildAppBundleCommand(projectPath);
53
      expect((await commandDefault.usageValues).commandBuildAppBundleBuildMode, 'release');
54

55
      final BuildAppBundleCommand commandInRelease = await runBuildAppBundleCommand(projectPath,
56
          arguments: <String>['--release']);
57
      expect((await commandInRelease.usageValues).commandBuildAppBundleBuildMode, 'release');
58

59
      final BuildAppBundleCommand commandInDebug = await runBuildAppBundleCommand(projectPath,
60
          arguments: <String>['--debug']);
61
      expect((await commandInDebug.usageValues).commandBuildAppBundleBuildMode, 'debug');
62

63
      final BuildAppBundleCommand commandInProfile = await runBuildAppBundleCommand(projectPath,
64
          arguments: <String>['--profile']);
65
      expect((await commandInProfile.usageValues).commandBuildAppBundleBuildMode, 'profile');
66 67 68

    }, overrides: <Type, Generator>{
      AndroidBuilder: () => FakeAndroidBuilder(),
69
    });
70 71 72 73 74 75 76

    testUsingContext('logs success', () async {
      final String projectPath = await createProject(tempDir,
          arguments: <String>['--no-pub', '--template=app']);

      await runBuildAppBundleCommand(projectPath);

77 78 79
      expect(testUsage.events, contains(
        const TestUsageEvent('tool-command-result', 'appbundle', label: 'success'),
      ));
80 81 82
    },
    overrides: <Type, Generator>{
      AndroidBuilder: () => FakeAndroidBuilder(),
83
      Usage: () => testUsage,
84
    });
85
  });
86

Emmanuel Garcia's avatar
Emmanuel Garcia committed
87
  group('Gradle', () {
88 89 90 91
    late Directory tempDir;
    late FakeProcessManager processManager;
    late FakeAndroidSdk fakeAndroidSdk;
    late TestUsage testUsage;
92 93

    setUp(() {
94
      testUsage = TestUsage();
95
      tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
96
      processManager = FakeProcessManager.any();
97
      fakeAndroidSdk = FakeAndroidSdk(globals.fs.directory('irrelevant'));
98 99 100 101 102 103
    });

    tearDown(() {
      tryToDelete(tempDir);
    });

104
    group('AndroidSdk', () {
105 106 107 108 109 110 111 112 113 114
      testUsingContext('throws throwsToolExit if AndroidSdk is null', () async {
        final String projectPath = await createProject(tempDir,
            arguments: <String>['--no-pub', '--template=app']);

        await expectLater(() async {
          await runBuildAppBundleCommand(
            projectPath,
            arguments: <String>['--no-pub'],
          );
        }, throwsToolExit(
115
          message: 'No Android SDK found. Try setting the ANDROID_SDK_ROOT environment variable',
116 117 118 119 120
        ));
      },
      overrides: <Type, Generator>{
        AndroidSdk: () => null,
        FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
121
        ProcessManager: () => processManager,
122 123 124
      });
    });

125
    testUsingContext("reports when the app isn't using AndroidX", () async {
126
      final String projectPath = await createProject(tempDir,
127 128 129 130 131 132 133
          arguments: <String>['--no-pub', '--template=app']);
      // Simulate a non-androidx project.
      tempDir
        .childDirectory('flutter_project')
        .childDirectory('android')
        .childFile('gradle.properties')
        .writeAsStringSync('android.useAndroidX=false');
134 135 136 137 138 139 140 141

      // The command throws a [ToolExit] because it expects an AAB in the file system.
      await expectLater(() async {
        await runBuildAppBundleCommand(
          projectPath,
        );
      }, throwsToolExit());

142 143 144 145 146 147 148
      expect(
        testLogger.statusText,
        containsIgnoringWhitespace("Your app isn't using AndroidX"),
      );
      expect(
        testLogger.statusText,
        containsIgnoringWhitespace(
149 150
        'To avoid potential build failures, you can quickly migrate your app by '
        'following the steps on https://goo.gl/CP92wY'
151
        ),
152
      );
153 154 155 156

      expect(testUsage.events, contains(
        const TestUsageEvent(
          'build',
157
          'gradle',
158
          label: 'app-not-using-android-x',
159
          parameters: CustomDimensions(),
160 161
        ),
      ));
162 163
    },
    overrides: <Type, Generator>{
164
      AndroidSdk: () => fakeAndroidSdk,
165
      FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
166
      ProcessManager: () => processManager,
167
      Usage: () => testUsage,
168
    });
169 170 171 172 173 174 175 176 177 178 179 180 181

    testUsingContext('reports when the app is using AndroidX', () async {
      final String projectPath = await createProject(tempDir,
          arguments: <String>['--no-pub', '--template=app']);

      // The command throws a [ToolExit] because it expects an AAB in the file system.
      await expectLater(() async {
        await runBuildAppBundleCommand(
          projectPath,
        );
      }, throwsToolExit());

      expect(
182
        testLogger.statusText,
183
        isNot(containsIgnoringWhitespace("Your app isn't using AndroidX")),
184 185 186
      );
      expect(
        testLogger.statusText,
187
        isNot(
188 189 190 191
          containsIgnoringWhitespace(
            'To avoid potential build failures, you can quickly migrate your app by '
            'following the steps on https://goo.gl/CP92wY'),
        )
192
      );
193 194 195 196

      expect(testUsage.events, contains(
        const TestUsageEvent(
          'build',
197
          'gradle',
198
          label: 'app-using-android-x',
199
          parameters: CustomDimensions(),
200 201
        ),
      ));
202 203
    },
    overrides: <Type, Generator>{
204
      AndroidSdk: () => fakeAndroidSdk,
205
      FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
206
      ProcessManager: () => processManager,
207
      Usage: () => testUsage,
208
    });
209
  });
210
}
211 212

Future<BuildAppBundleCommand> runBuildAppBundleCommand(
213
  String target, {
214
  List<String>? arguments,
215
}) async {
216 217 218 219 220
  final BuildAppBundleCommand command = BuildAppBundleCommand();
  final CommandRunner<void> runner = createTestCommandRunner(command);
  await runner.run(<String>[
    'appbundle',
    ...?arguments,
221
    '--no-pub',
222
    globals.fs.path.join(target, 'lib', 'main.dart'),
223 224 225 226
  ]);
  return command;
}

227 228
class FakeAndroidSdk extends Fake implements AndroidSdk {
  FakeAndroidSdk(this.directory);
kwkr's avatar
kwkr committed
229

230 231 232
  @override
  final Directory directory;
}