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

import 'package:file/memory.dart';
6
import 'package:flutter_tools/src/aot.dart';
7 8
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/process.dart';
9
import 'package:flutter_tools/src/build_info.dart';
10
import 'package:flutter_tools/src/base/file_system.dart';
11
import 'package:flutter_tools/src/build_system/build_system.dart';
xster's avatar
xster committed
12
import 'package:flutter_tools/src/ios/bitcode.dart';
13
import 'package:flutter_tools/src/ios/plist_parser.dart';
14 15 16
import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
17
import 'package:flutter_tools/src/globals.dart' as globals;
18 19 20 21 22 23 24 25 26

import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart';

void main() {
  MockXcode mockXcode;
  MemoryFileSystem memoryFileSystem;
  MockProcessManager mockProcessManager;
27
  MockPlistUtils mockPlistUtils;
28 29 30 31 32

  setUp(() {
    mockXcode = MockXcode();
    memoryFileSystem = MemoryFileSystem(style: FileSystemStyle.posix);
    mockProcessManager = MockProcessManager();
33
    mockPlistUtils = MockPlistUtils();
34 35 36 37
  });

  testUsingContext('build aot validates existence of Flutter.framework in engine', () async {
    await expectToolExitLater(
38
      validateBitcode(BuildMode.release, TargetPlatform.ios),
39 40 41
      equals('Flutter.framework not found at ios_profile/Flutter.framework'),
    );
  }, overrides: <Type, Generator>{
42
    Artifacts: () => LocalEngineArtifacts('ios_profile', 'host_profile',
43 44 45 46 47
      fileSystem: memoryFileSystem,
      cache: globals.cache,
      platform: globals.platform,
      processManager: mockProcessManager,
    ),
48
    FileSystem: () => memoryFileSystem,
49
    ProcessManager: () => FakeProcessManager.any(),
50 51
  });

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
  testUsingContext('build aot prints error if Clang version invalid', () async {
    final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework')
      ..createSync(recursive: true);
    flutterFramework.childFile('Flutter').createSync();
    final File infoPlist = flutterFramework.childFile('Info.plist')..createSync();

    final RunResult clangResult = RunResult(
      FakeProcessResult(stdout: 'Apple pie version 10.1.0 (clang-4567.1.1.1)\nBlahBlah\n', stderr: ''),
      const <String>['foo'],
    );
    when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(clangResult));
    when(mockPlistUtils.getValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM version 10.0.1 (clang-1234.1.12.1)');

    await expectToolExitLater(
      validateBitcode(BuildMode.profile, TargetPlatform.ios),
      equals('Unable to parse Clang version from "Apple pie version 10.1.0 (clang-4567.1.1.1)". '
             'Expected a string like "Apple (LLVM|clang) #.#.# (clang-####.#.##.#)".'),
    );
  }, overrides: <Type, Generator>{
71
    Artifacts: () => LocalEngineArtifacts('ios_profile', 'host_profile',
72 73 74 75 76
      fileSystem: memoryFileSystem,
      cache: globals.cache,
      platform: globals.platform,
      processManager: mockProcessManager,
    ),
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    FileSystem: () => memoryFileSystem,
    ProcessManager: () => mockProcessManager,
    Xcode: () => mockXcode,
    PlistParser: () => mockPlistUtils,
  });

  testUsingContext('build aot can parse valid Xcode Clang version (10)', () async {
    final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework')
      ..createSync(recursive: true);
    flutterFramework.childFile('Flutter').createSync();
    final File infoPlist = flutterFramework.childFile('Info.plist')..createSync();

    final RunResult clangResult = RunResult(
      FakeProcessResult(stdout: 'Apple LLVM version 10.1.0 (clang-4567.1.1.1)\nBlahBlah\n', stderr: ''),
      const <String>['foo'],
    );
    when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(clangResult));
    when(mockPlistUtils.getValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM version 10.0.1 (clang-1234.1.12.1)');

    await validateBitcode(BuildMode.profile, TargetPlatform.ios);

  }, overrides: <Type, Generator>{
99
    Artifacts: () => LocalEngineArtifacts('ios_profile', 'host_profile',
100 101 102 103 104
      fileSystem: memoryFileSystem,
      cache: globals.cache,
      platform: globals.platform,
      processManager: mockProcessManager,
    ),
105 106 107 108 109 110
    FileSystem: () => memoryFileSystem,
    ProcessManager: () => mockProcessManager,
    Xcode: () => mockXcode,
    PlistParser: () => mockPlistUtils,
  });

111
  testUsingContext('build aot outputs timing info', () async {
112
    globals.fs
113
      .file('.dart_tool/flutter_build/3f206b606f73e08587a94405f2e86fad/app.so')
114
      .createSync(recursive: true);
115
    when(globals.buildSystem.build(any, any))
116 117 118 119 120 121
      .thenAnswer((Invocation invocation) async {
        return BuildResult(success: true, performance: <String, PerformanceMeasurement>{
          'kernel_snapshot': PerformanceMeasurement(
            analyicsName: 'kernel_snapshot',
            target: 'kernel_snapshot',
            elapsedMilliseconds: 1000,
122
            succeeded: true,
123 124 125 126 127 128
            skipped: false,
          ),
          'anything': PerformanceMeasurement(
            analyicsName: 'android_aot',
            target: 'anything',
            elapsedMilliseconds: 1000,
129
            succeeded: true,
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
            skipped: false,
          ),
        });
      });

    await AotBuilder().build(
      platform: TargetPlatform.android_arm64,
      outputPath: '/',
      buildInfo: BuildInfo.release,
      mainDartFile: globals.fs.path.join('lib', 'main.dart'),
      reportTimings: true,
    );

    expect(testLogger.statusText, allOf(
      contains('frontend(CompileTime): 1000 ms.'),
      contains('snapshot(CompileTime): 1000 ms.'),
    ));
  }, overrides: <Type, Generator>{
    BuildSystem: () => MockBuildSystem(),
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
  });


154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
  testUsingContext('build aot can parse valid Xcode Clang version (11)', () async {
    final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework')
      ..createSync(recursive: true);
    flutterFramework.childFile('Flutter').createSync();
    final File infoPlist = flutterFramework.childFile('Info.plist')..createSync();

    final RunResult clangResult = RunResult(
      FakeProcessResult(stdout: 'Apple clang version 11.0.0 (clang-4567.1.1.1)\nBlahBlah\n', stderr: ''),
      const <String>['foo'],
    );
    when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(clangResult));
    when(mockPlistUtils.getValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM version 10.0.1 (clang-1234.1.12.1)');

    await validateBitcode(BuildMode.profile, TargetPlatform.ios);
  }, overrides: <Type, Generator>{
169
    Artifacts: () => LocalEngineArtifacts('ios_profile', 'host_profile',
170 171 172 173 174
      fileSystem: memoryFileSystem,
      cache: globals.cache,
      platform: globals.platform,
      processManager: mockProcessManager,
    ),
175 176 177 178 179 180
    FileSystem: () => memoryFileSystem,
    ProcessManager: () => mockProcessManager,
    Xcode: () => mockXcode,
    PlistParser: () => mockPlistUtils,
  });

181 182 183 184 185 186 187
  testUsingContext('build aot validates Flutter.framework/Flutter was built with same toolchain', () async {
    final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework')
      ..createSync(recursive: true);
    flutterFramework.childFile('Flutter').createSync();
    final File infoPlist = flutterFramework.childFile('Info.plist')..createSync();

    final RunResult clangResult = RunResult(
188
      FakeProcessResult(stdout: 'Apple LLVM version 10.0.0 (clang-4567.1.1.1)\nBlahBlah\n', stderr: ''),
189 190 191
      const <String>['foo'],
    );
    when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(clangResult));
192
    when(mockPlistUtils.getValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM version 10.0.1 (clang-1234.1.12.1)');
193

194
    await expectToolExitLater(
195
      validateBitcode(BuildMode.release, TargetPlatform.ios),
196 197
      equals('The Flutter.framework at ios_profile/Flutter.framework was built with "Apple LLVM version 10.0.1 '
             '(clang-1234.1.12.1)", but the current version of clang is "Apple LLVM version 10.0.0 (clang-4567.1.1.1)". '
198
             'This will result in failures when trying to archive an IPA. To resolve this issue, update your version '
199 200 201
             'of Xcode to at least 10.0.1.'),
    );
  }, overrides: <Type, Generator>{
202
    Artifacts: () => LocalEngineArtifacts('ios_profile', 'host_profile',
203 204 205 206 207
      fileSystem: memoryFileSystem,
      cache: globals.cache,
      platform: globals.platform,
      processManager: mockProcessManager,
    ),
208 209 210
    FileSystem: () => memoryFileSystem,
    ProcessManager: () => mockProcessManager,
    Xcode: () => mockXcode,
211
    PlistParser: () => mockPlistUtils,
212
  });
213

214 215 216 217 218 219 220 221 222
  testUsingContext('build aot validates and succeeds - same version of Xcode', () async {
    final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework')
      ..createSync(recursive: true);
    flutterFramework.childFile('Flutter').createSync();
    final File infoPlist = flutterFramework.childFile('Info.plist')..createSync();

    final RunResult clangResult = RunResult(
      FakeProcessResult(stdout: 'Apple LLVM version 10.0.1 (clang-1234.1.12.1)\nBlahBlah\n', stderr: ''),
      const <String>['foo'],
223
    );
224
    when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(clangResult));
225
    when(mockPlistUtils.getValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM version 10.0.1 (clang-1234.1.12.1)');
226

227
    await validateBitcode(BuildMode.release, TargetPlatform.ios);
228

229
    expect(testLogger.statusText, '');
230
  }, overrides: <Type, Generator>{
231
    Artifacts: () => LocalEngineArtifacts('ios_profile', 'host_profile',
232 233 234 235 236
      fileSystem: memoryFileSystem,
      cache: globals.cache,
      platform: globals.platform,
      processManager: mockProcessManager,
    ),
237 238 239
    FileSystem: () => memoryFileSystem,
    ProcessManager: () => mockProcessManager,
    Xcode: () => mockXcode,
240
    PlistParser: () => mockPlistUtils,
241 242
  });

243
  testUsingContext('build aot validates and succeeds when user has newer version of Xcode', () async {
244 245 246 247 248 249
    final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework')
      ..createSync(recursive: true);
    flutterFramework.childFile('Flutter').createSync();
    final File infoPlist = flutterFramework.childFile('Info.plist')..createSync();

    final RunResult clangResult = RunResult(
250
      FakeProcessResult(stdout: 'Apple LLVM version 11.0.1 (clang-1234.1.12.1)\nBlahBlah\n', stderr: ''),
251 252 253
      const <String>['foo'],
    );
    when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(clangResult));
254
    when(mockPlistUtils.getValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM version 10.0.1 (clang-1234.1.12.1)');
255

256
    await validateBitcode(BuildMode.release, TargetPlatform.ios);
257

258
    expect(testLogger.statusText, '');
259
  }, overrides: <Type, Generator>{
260
    Artifacts: () => LocalEngineArtifacts('ios_profile', 'host_profile',
261 262 263 264 265
      fileSystem: memoryFileSystem,
      cache: globals.cache,
      platform: globals.platform,
      processManager: mockProcessManager,
    ),
266 267 268
    FileSystem: () => memoryFileSystem,
    ProcessManager: () => mockProcessManager,
    Xcode: () => mockXcode,
269
    PlistParser: () => mockPlistUtils,
270 271 272 273
  });
}

class MockXcode extends Mock implements Xcode {}
274
class MockPlistUtils extends Mock implements PlistParser {}
275
class MockBuildSystem extends Mock implements BuildSystem {}