web_dev_mode_tests.dart 7.01 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
// 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'));
15
final Directory flutterGalleryDir = dir(path.join(flutterDirectory.path, 'dev/integration_tests/flutter_gallery'));
16

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 50 51 52 53
    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'],
          );
          await packagesGet.exitCode;
          final Process process = await startProcess(
              path.join(flutterDirectory.path, 'bin', 'flutter'),
              flutterCommandArgs('run', options),
          );
54

55 56 57
          final Completer<void> stdoutDone = Completer<void>();
          final Completer<void> stderrDone = Completer<void>();
          final Stopwatch sw = Stopwatch()..start();
58
          bool restarted = false;
59 60 61 62
          process.stdout
              .transform<String>(utf8.decoder)
              .transform<String>(const LineSplitter())
              .listen((String line) {
63 64 65 66 67 68 69
            // 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;
            }
70 71 72 73 74 75 76
            if (line.contains('To hot restart')) {
              // measure clean start-up time.
              sw.stop();
              measurements[kInitialStartupTime] = sw.elapsedMilliseconds;
              sw
                ..reset()
                ..start();
77 78
              process.stdin.write('r');
              return;
79
            }
80
            if (line.contains(expectedMessage)) {
81 82 83 84 85 86 87 88 89 90 91 92 93 94
              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();
95
                process.stdin.writeln('r');
96 97
                ++hotRestartCount;
              } else {
98
                restarted = true;
99 100 101
                measurements[kFirstRecompileTime] = sw.elapsedMilliseconds;
                // Quit after second hot restart.
                process.stdin.writeln('q');
102
              }
103 104 105 106 107 108 109 110 111 112 113 114 115
            }
            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();
          });
116

117 118 119 120 121
          await Future.wait<void>(<Future<void>>[
            stdoutDone.future,
            stderrDone.future,
          ]);
          await process.exitCode;
122

123
        }
124

125 126 127 128 129 130 131 132 133 134 135
        // 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),
          );
          final Completer<void> stdoutDone = Completer<void>();
          final Completer<void> stderrDone = Completer<void>();
136
          bool restarted = false;
137 138 139 140
          process.stdout
              .transform<String>(utf8.decoder)
              .transform<String>(const LineSplitter())
              .listen((String line) {
141 142 143 144 145 146 147
            // 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;
            }
148 149 150 151 152
            if (line.contains('To hot restart')) {
              measurements[kSecondStartupTime] = sw.elapsedMilliseconds;
              sw
                ..reset()
                ..start();
153 154
              process.stdin.write('r');
              return;
155
            }
156 157 158
            if (line.contains(expectedMessage)) {
              restarted = true;
              measurements[kSecondRestartTime] = sw.elapsedMilliseconds;
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
              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;
        }
180
      });
181
    });
182 183 184
    if (hotRestartCount != 1) {
      return TaskResult.failure(null);
    }
185 186 187 188 189 190 191
    return TaskResult.success(measurements, benchmarkScoreKeys: <String>[
      kInitialStartupTime,
      kFirstRestartTime,
      kFirstRecompileTime,
      kSecondStartupTime,
      kSecondRestartTime,
    ]);
192 193
  };
}