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

5 6
// @dart = 2.8

7 8
import 'package:args/command_runner.dart';
import 'package:flutter_tools/src/android/android_builder.dart';
9
import 'package:flutter_tools/src/android/android_sdk.dart';
10 11 12
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';
13
import 'package:flutter_tools/src/globals.dart' as globals;
14
import 'package:flutter_tools/src/project.dart';
15
import 'package:flutter_tools/src/reporting/reporting.dart';
16
import 'package:test/fake.dart';
17

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

void main() {
  Cache.disableLocking();

26
  group('Usage', () {
27
    Directory tempDir;
28
    TestUsage testUsage;
29 30

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

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

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

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

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

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

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

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

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

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

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

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

      await runBuildAppBundleCommand(projectPath);

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

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

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

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

106
    group('AndroidSdk', () {
107 108 109 110 111 112 113 114 115 116
      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(
117
          message: 'No Android SDK found. Try setting the ANDROID_SDK_ROOT environment variable',
118 119 120 121 122
        ));
      },
      overrides: <Type, Generator>{
        AndroidSdk: () => null,
        FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
123
        ProcessManager: () => processManager,
124 125 126
      });
    });

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

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

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

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

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

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

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

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

232 233 234
  @override
  final Directory directory;
}