gradle_plugin_test.dart 5.89 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:io';

import 'package:path/path.dart' as path;
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/utils.dart';

void main() {
  task(() async {
    section('Setting up flutter project');
    final Directory tmp = await Directory.systemTemp.createTemp('gradle');
    final FlutterProject project = await FlutterProject.create(tmp, 'hello');

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    try {
      section('gradlew assembleDebug');
      await project.runGradleTask('assembleDebug');

      section('gradlew assembleProfile');
      await project.runGradleTask('assembleProfile');

      section('gradlew assembleRelease');
      await project.runGradleTask('assembleRelease');

      section('gradlew assembleLocal (custom debug build)');
      await project.addCustomBuildType('local', initWith: 'debug');
      await project.runGradleTask('assembleLocal');

      section('gradlew assembleBeta (custom release build)');
      await project.addCustomBuildType('beta', initWith: 'release');
      await project.runGradleTask('assembleBeta');

      section('gradlew assembleFreeDebug (product flavor)');
      await project.addProductFlavor('free');
      await project.runGradleTask('assembleFreeDebug');

      await project.introduceError();

      section('gradlew on build script with error');
      {
        final ProcessResult result = await project.resultOfGradleTask('assembleRelease');
        if (result.exitCode == 0)
          return _failure('Gradle did not exit with error as expected', result);
        final String output = result.stdout + '\n' + result.stderr;
        if (output.contains('GradleException') || output.contains('Failed to notify') || output.contains('at org.gradle'))
          return _failure('Gradle output should not contain stacktrace', result);
        if (!output.contains('Build failed') || !output.contains('builTypes'))
          return _failure('Gradle output should contain a readable error message', result);
      }

      section('flutter build apk on build script with error');
      {
        final ProcessResult result = await project.resultOfFlutterCommand('build', <String>['apk']);
        if (result.exitCode == 0)
          return _failure('flutter build apk should fail when Gradle does', result);
        final String output = result.stdout + '\n' + result.stderr;
        if (!output.contains('Build failed') || !output.contains('builTypes'))
          return _failure('flutter build apk output should contain a readable Gradle error message', result);
        if (_hasMultipleOccurrences(output, 'builTypes'))
          return _failure('flutter build apk should not invoke Gradle repeatedly on error', result);
      }

      return new TaskResult.success(null);
    } catch(e) {
      return new TaskResult.failure(e.toString());
    } finally {
      project.parent.deleteSync(recursive: true);
    }
  });
}
74

75 76 77 78 79 80 81
TaskResult _failure(String message, ProcessResult result) {
  print('Unexpected process result:');
  print('Exit code: ${result.exitCode}');
  print('Std out  :\n${result.stdout}');
  print('Std err  :\n${result.stderr}');
  return new TaskResult.failure(message);
}
82

83 84
bool _hasMultipleOccurrences(String text, Pattern pattern) {
  return text.indexOf(pattern) != text.lastIndexOf(pattern);
85 86 87
}

class FlutterProject {
88
  FlutterProject(this.parent, this.name, this.javaPath);
89

90 91 92
  final Directory parent;
  final String name;
  final String javaPath;
93 94 95 96 97

  static Future<FlutterProject> create(Directory directory, String name) async {
    await inDirectory(directory, () async {
      await flutter('create', options: <String>[name]);
    });
98 99 100 101
    final String flutterDoctor = await evalFlutter('doctor');
    final RegExp javaPathExtractor = new RegExp(r'Android Studio at (.*)');
    final String javaPath = javaPathExtractor.firstMatch(flutterDoctor).group(1) + '/jre';
    return new FlutterProject(directory, name, javaPath);
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
  }

  String get rootPath => path.join(parent.path, name);
  String get androidPath => path.join(rootPath, 'android');

  Future<Null> addCustomBuildType(String name, {String initWith}) async {
    final File buildScript = new File(
      path.join(androidPath, 'app', 'build.gradle'),
    );
    buildScript.openWrite(mode: FileMode.APPEND).write('''

android {
    buildTypes {
        $name {
            initWith $initWith
        }
    }
}
    ''');
  }

  Future<Null> addProductFlavor(String name) async {
    final File buildScript = new File(
      path.join(androidPath, 'app', 'build.gradle'),
    );
    buildScript.openWrite(mode: FileMode.APPEND).write('''

android {
    productFlavors {
        $name {
            applicationIdSuffix ".$name"
            versionNameSuffix "-$name"
        }
    }
}
    ''');
  }

140 141 142
  Future<Null> introduceError() async {
    final File buildScript = new File(
      path.join(androidPath, 'app', 'build.gradle'),
143
    );
144 145 146 147 148
    await buildScript.writeAsString((await buildScript.readAsString()).replaceAll('buildTypes', 'builTypes'));
  }

  Future<Null> runGradleTask(String task) async {
    final ProcessResult result = await resultOfGradleTask(task);
149 150 151 152 153 154
    if (result.exitCode != 0) {
      print('stdout:');
      print(result.stdout);
      print('stderr:');
      print(result.stderr);
    }
155 156 157 158 159 160 161 162 163
    if (result.exitCode != 0)
      throw 'Gradle exited with error';
  }

  Future<ProcessResult> resultOfGradleTask(String task) {
    return Process.run(
      './gradlew',
      <String>['app:$task'],
      workingDirectory: androidPath,
164
      environment: <String, String>{ 'JAVA_HOME': javaPath }
165 166 167 168 169 170 171 172 173
    );
  }

  Future<ProcessResult> resultOfFlutterCommand(String command, List<String> options) {
    return Process.run(
      path.join(flutterDirectory.path, 'bin', 'flutter'),
      <String>[command]..addAll(options),
      workingDirectory: rootPath,
    );
174 175
  }
}