web_dev_mode_tests.dart 7.59 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 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:convert';
import 'dart:io';

import 'package:path/path.dart' as path;

import '../framework/framework.dart';
import '../framework/utils.dart';

final Directory _editedFlutterGalleryDir = dir(path.join(Directory.systemTemp.path, 'edited_flutter_gallery'));
final Directory flutterGalleryDir = dir(path.join(flutterDirectory.path, 'examples/flutter_gallery'));

17 18 19 20 21 22
const String kInitialStartupTime = 'InitialStartupTime';
const String kFirstRestartTime = 'FistRestartTime';
const String kFirstRecompileTime  = 'FirstRecompileTime';
const String kSecondStartupTime = 'SecondStartupTime';
const String kSecondRestartTime = 'SecondRestartTime';

23 24 25 26 27 28 29

abstract class WebDevice {
  static const String chrome = 'chrome';
  static const String webServer = 'web-server';
}

TaskFunction createWebDevModeTest(String webDevice, bool enableIncrementalCompiler) {
30 31
  return () async {
    final List<String> options = <String>[
32
      '--hot', '-d', webDevice, '--verbose', '--resident', '--target=lib/main.dart',
33 34
    ];
    int hotRestartCount = 0;
35 36 37
    final String expectedMessage = webDevice == WebDevice.webServer
      ? 'Recompile complete'
      : 'Reloaded application';
38 39 40 41 42 43 44 45 46 47 48 49
    final Map<String, int> measurements = <String, int>{};
    await inDirectory<void>(flutterDirectory, () async {
      rmTree(_editedFlutterGalleryDir);
      mkdirs(_editedFlutterGalleryDir);
      recursiveCopy(flutterGalleryDir, _editedFlutterGalleryDir);
      await inDirectory<void>(_editedFlutterGalleryDir, () async {
        {
          final Process packagesGet = await startProcess(
              path.join(flutterDirectory.path, 'bin', 'flutter'),
              <String>['packages', 'get'],
              environment: <String, String>{
                'FLUTTER_WEB': 'true',
50 51
                if (enableIncrementalCompiler)
                  'WEB_INCREMENTAL_COMPILER': 'true',
52 53 54 55 56 57 58 59
              },
          );
          await packagesGet.exitCode;
          final Process process = await startProcess(
              path.join(flutterDirectory.path, 'bin', 'flutter'),
              flutterCommandArgs('run', options),
              environment: <String, String>{
                'FLUTTER_WEB': 'true',
60 61
                if (enableIncrementalCompiler)
                  'WEB_INCREMENTAL_COMPILER': 'true',
62 63
              },
          );
64

65 66 67
          final Completer<void> stdoutDone = Completer<void>();
          final Completer<void> stderrDone = Completer<void>();
          final Stopwatch sw = Stopwatch()..start();
68
          bool restarted = false;
69 70 71 72
          process.stdout
              .transform<String>(utf8.decoder)
              .transform<String>(const LineSplitter())
              .listen((String line) {
73 74 75 76 77 78 79
            // TODO(jonahwilliams): non-dwds builds do not know when the browser is loaded.
            if (line.contains('Ignoring terminal input')) {
              Future<void>.delayed(const Duration(seconds: 1)).then((void _) {
                process.stdin.write(restarted ? 'q' : 'r');
              });
              return;
            }
80 81 82 83 84 85 86
            if (line.contains('To hot restart')) {
              // measure clean start-up time.
              sw.stop();
              measurements[kInitialStartupTime] = sw.elapsedMilliseconds;
              sw
                ..reset()
                ..start();
87 88
              process.stdin.write('r');
              return;
89
            }
90
            if (line.contains(expectedMessage)) {
91 92 93 94 95 96 97 98 99 100 101 102 103 104
              if (hotRestartCount == 0) {
                measurements[kFirstRestartTime] = sw.elapsedMilliseconds;
                // Update the file and reload again.
                final File appDartSource = file(path.join(
                    _editedFlutterGalleryDir.path, 'lib/gallery/app.dart',
                ));
                appDartSource.writeAsStringSync(
                    appDartSource.readAsStringSync().replaceFirst(
                        "'Flutter Gallery'", "'Updated Flutter Gallery'",
                    )
                );
                sw
                  ..reset()
                  ..start();
105
                process.stdin.writeln('r');
106 107
                ++hotRestartCount;
              } else {
108
                restarted = true;
109 110 111
                measurements[kFirstRecompileTime] = sw.elapsedMilliseconds;
                // Quit after second hot restart.
                process.stdin.writeln('q');
112
              }
113 114 115 116 117 118 119 120 121 122 123 124 125
            }
            print('stdout: $line');
          }, onDone: () {
            stdoutDone.complete();
          });
          process.stderr
              .transform<String>(utf8.decoder)
              .transform<String>(const LineSplitter())
              .listen((String line) {
            print('stderr: $line');
          }, onDone: () {
            stderrDone.complete();
          });
126

127 128 129 130 131
          await Future.wait<void>(<Future<void>>[
            stdoutDone.future,
            stderrDone.future,
          ]);
          await process.exitCode;
132

133
        }
134

135 136 137 138 139 140 141 142 143 144
        // Start `flutter run` again to make sure it loads from the previous
        // state. dev compilers loads up from previously compiled JavaScript.
        {

          final Stopwatch sw = Stopwatch()..start();
          final Process process = await startProcess(
              path.join(flutterDirectory.path, 'bin', 'flutter'),
              flutterCommandArgs('run', options),
              environment: <String, String>{
                'FLUTTER_WEB': 'true',
145 146
                if (enableIncrementalCompiler)
                  'WEB_INCREMENTAL_COMPILER': 'true',
147 148 149 150
              },
          );
          final Completer<void> stdoutDone = Completer<void>();
          final Completer<void> stderrDone = Completer<void>();
151
          bool restarted = false;
152 153 154 155
          process.stdout
              .transform<String>(utf8.decoder)
              .transform<String>(const LineSplitter())
              .listen((String line) {
156 157 158 159 160 161 162
            // TODO(jonahwilliams): non-dwds builds do not know when the browser is loaded.
            if (line.contains('Ignoring terminal input')) {
              Future<void>.delayed(const Duration(seconds: 1)).then((void _) {
                process.stdin.write(restarted ? 'q' : 'r');
              });
              return;
            }
163 164 165 166 167
            if (line.contains('To hot restart')) {
              measurements[kSecondStartupTime] = sw.elapsedMilliseconds;
              sw
                ..reset()
                ..start();
168 169
              process.stdin.write('r');
              return;
170
            }
171 172 173
            if (line.contains(expectedMessage)) {
              restarted = true;
              measurements[kSecondRestartTime] = sw.elapsedMilliseconds;
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
              process.stdin.writeln('q');
            }
            print('stdout: $line');
          }, onDone: () {
            stdoutDone.complete();
          });
          process.stderr
              .transform<String>(utf8.decoder)
              .transform<String>(const LineSplitter())
              .listen((String line) {
            print('stderr: $line');
          }, onDone: () {
            stderrDone.complete();
          });

          await Future.wait<void>(<Future<void>>[
            stdoutDone.future,
            stderrDone.future,
          ]);
          await process.exitCode;
        }
195
      });
196
    });
197 198 199
    if (hotRestartCount != 1) {
      return TaskResult.failure(null);
    }
200 201 202 203 204 205 206
    return TaskResult.success(measurements, benchmarkScoreKeys: <String>[
      kInitialStartupTime,
      kFirstRestartTime,
      kFirstRecompileTime,
      kSecondStartupTime,
      kSecondRestartTime,
    ]);
207 208
  };
}