web_dev_mode_tests.dart 7.11 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
// 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';
12
import '../framework/task_result.dart';
13 14 15
import '../framework/utils.dart';

final Directory _editedFlutterGalleryDir = dir(path.join(Directory.systemTemp.path, 'edited_flutter_gallery'));
16
final Directory flutterGalleryDir = dir(path.join(flutterDirectory.path, 'dev/integration_tests/flutter_gallery'));
17

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

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
            // non-dwds builds do not know when the browser is loaded so keep trying
            // until this succeeds.
65 66 67 68 69 70
            if (line.contains('Ignoring terminal input')) {
              Future<void>.delayed(const Duration(seconds: 1)).then((void _) {
                process.stdin.write(restarted ? 'q' : 'r');
              });
              return;
            }
71 72 73 74 75 76 77
            if (line.contains('To hot restart')) {
              // measure clean start-up time.
              sw.stop();
              measurements[kInitialStartupTime] = sw.elapsedMilliseconds;
              sw
                ..reset()
                ..start();
78 79
              process.stdin.write('r');
              return;
80
            }
81
            if (line.contains(expectedMessage)) {
82 83 84 85 86 87 88 89 90 91 92 93 94 95
              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();
96
                process.stdin.writeln('r');
97 98
                ++hotRestartCount;
              } else {
99
                restarted = true;
100 101 102
                measurements[kFirstRecompileTime] = sw.elapsedMilliseconds;
                // Quit after second hot restart.
                process.stdin.writeln('q');
103
              }
104 105 106 107 108 109 110 111 112 113 114 115 116
            }
            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();
          });
117

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

124
        }
125

126 127 128 129 130 131 132 133 134 135 136
        // 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>();
137
          bool restarted = false;
138 139 140 141
          process.stdout
              .transform<String>(utf8.decoder)
              .transform<String>(const LineSplitter())
              .listen((String line) {
142 143
            // non-dwds builds do not know when the browser is loaded so keep trying
            // until this succeeds.
144 145 146 147 148 149
            if (line.contains('Ignoring terminal input')) {
              Future<void>.delayed(const Duration(seconds: 1)).then((void _) {
                process.stdin.write(restarted ? 'q' : 'r');
              });
              return;
            }
150 151 152 153 154
            if (line.contains('To hot restart')) {
              measurements[kSecondStartupTime] = sw.elapsedMilliseconds;
              sw
                ..reset()
                ..start();
155 156
              process.stdin.write('r');
              return;
157
            }
158 159 160
            if (line.contains(expectedMessage)) {
              restarted = true;
              measurements[kSecondRestartTime] = sw.elapsedMilliseconds;
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
              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;
        }
182
      });
183
    });
184 185 186
    if (hotRestartCount != 1) {
      return TaskResult.failure(null);
    }
187 188 189 190 191 192 193
    return TaskResult.success(measurements, benchmarkScoreKeys: <String>[
      kInitialStartupTime,
      kFirstRestartTime,
      kFirstRecompileTime,
      kSecondStartupTime,
      kSecondRestartTime,
    ]);
194 195
  };
}