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

5 6
// @dart = 2.8

7 8
import 'dart:async';

9
import 'package:file/memory.dart';
10
import 'package:flutter_tools/src/application_package.dart';
11
import 'package:flutter_tools/src/base/common.dart';
12
import 'package:flutter_tools/src/base/file_system.dart';
13
import 'package:flutter_tools/src/base/logger.dart';
14
import 'package:flutter_tools/src/base/time.dart';
15
import 'package:flutter_tools/src/build_info.dart';
16
import 'package:flutter_tools/src/build_system/build_system.dart';
17
import 'package:flutter_tools/src/devfs.dart';
18
import 'package:flutter_tools/src/device.dart';
19 20
import 'package:flutter_tools/src/isolated/devfs_web.dart';
import 'package:flutter_tools/src/isolated/resident_web_runner.dart';
21
import 'package:flutter_tools/src/project.dart';
22
import 'package:flutter_tools/src/reporting/reporting.dart';
23
import 'package:flutter_tools/src/resident_runner.dart';
24 25
import 'package:flutter_tools/src/vmservice.dart';
import 'package:test/fake.dart';
26 27

import '../src/common.dart';
28
import '../src/context.dart';
29
import '../src/test_build_system.dart';
30 31

void main() {
32 33 34
  FakeFlutterDevice mockFlutterDevice;
  FakeWebDevFS mockWebDevFS;
  FileSystem fileSystem;
35 36

  setUp(() {
37 38 39 40 41 42 43 44 45 46
    fileSystem = MemoryFileSystem.test();
    mockWebDevFS = FakeWebDevFS();
    final FakeWebDevice mockWebDevice = FakeWebDevice();
    mockFlutterDevice = FakeFlutterDevice(mockWebDevice);
    mockFlutterDevice._devFS = mockWebDevFS;

    fileSystem.file('.packages').writeAsStringSync('\n');
    fileSystem.file('pubspec.yaml').createSync();
    fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
    fileSystem.file(fileSystem.path.join('web', 'index.html')).createSync(recursive: true);
47 48
  });

49 50 51
  testUsingContext('Can successfully run and connect without vmservice', () async {
    final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory);
    final ResidentWebRunner residentWebRunner = ResidentWebRunner(
52 53 54 55 56
      mockFlutterDevice,
      flutterProject: project,
      debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
      ipv6: true,
      urlTunneller: null,
57 58 59 60
      fileSystem: fileSystem,
      logger: BufferLogger.test(),
      systemClock: SystemClock.fixed(DateTime(0, 0, 0)),
      usage: TestUsage(),
61
    );
62 63 64 65 66 67 68 69

    final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
    unawaited(residentWebRunner.run(
      connectionInfoCompleter: connectionInfoCompleter,
    ));
    final DebugConnectionInfo debugConnectionInfo = await connectionInfoCompleter.future;

    expect(debugConnectionInfo.wsUri, null);
70
  }, overrides: <Type, Generator>{
71
    BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
72
    FileSystem: () => fileSystem,
73 74
    ProcessManager: () => FakeProcessManager.any(),
  });
75

76
  // Regression test for https://github.com/flutter/flutter/issues/60613
77
  testUsingContext('ResidentWebRunner calls appFailedToStart if initial compilation fails', () async {
78 79 80 81 82 83 84 85 86 87 88 89
    final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory);
    final ResidentWebRunner residentWebRunner = ResidentWebRunner(
      mockFlutterDevice,
      flutterProject: project,
      debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
      ipv6: true,
      urlTunneller: null,
      fileSystem: fileSystem,
      logger: BufferLogger.test(),
      systemClock: SystemClock.fixed(DateTime(0, 0, 0)),
      usage: TestUsage(),
    );
90

91
    expect(() => residentWebRunner.run(), throwsToolExit());
92 93
    expect(await residentWebRunner.waitForAppToFinish(), 1);
  }, overrides: <Type, Generator>{
94
    BuildSystem: () => TestBuildSystem.all(BuildResult(success: false)),
95
    FileSystem: () => fileSystem,
96 97
    ProcessManager: () => FakeProcessManager.any(),
  });
98 99

  // Regression test for https://github.com/flutter/flutter/issues/60613
100
  testUsingContext('ResidentWebRunner calls appFailedToStart if error is thrown during startup', () async {
101 102 103 104 105 106 107 108 109 110 111 112
    final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory);
    final ResidentWebRunner residentWebRunner = ResidentWebRunner(
      mockFlutterDevice,
      flutterProject: project,
      debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
      ipv6: true,
      urlTunneller: null,
      fileSystem: fileSystem,
      logger: BufferLogger.test(),
      systemClock: SystemClock.fixed(DateTime(0, 0, 0)),
      usage: TestUsage(),
    );
113

114
    expect(() async => residentWebRunner.run(), throwsException);
115 116
    expect(await residentWebRunner.waitForAppToFinish(), 1);
  }, overrides: <Type, Generator>{
117
    BuildSystem: () => TestBuildSystem.error(Exception('foo')),
118
    FileSystem: () => fileSystem,
119 120
    ProcessManager: () => FakeProcessManager.any(),
  });
121

122
  testUsingContext('Can full restart after attaching', () async {
123 124 125 126 127 128 129 130 131 132 133 134
    final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory);
    final ResidentWebRunner residentWebRunner = ResidentWebRunner(
      mockFlutterDevice,
      flutterProject: project,
      debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
      ipv6: true,
      urlTunneller: null,
      fileSystem: fileSystem,
      logger: BufferLogger.test(),
      systemClock: SystemClock.fixed(DateTime(0, 0, 0)),
      usage: TestUsage(),
    );
135
    final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
136
    unawaited(residentWebRunner.run(
137 138 139 140 141 142
      connectionInfoCompleter: connectionInfoCompleter,
    ));
    await connectionInfoCompleter.future;
    final OperationResult result = await residentWebRunner.restart(fullRestart: true);

    expect(result.code, 0);
143
  }, overrides: <Type, Generator>{
144
    BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
145
    FileSystem: () => fileSystem,
146 147
    ProcessManager: () => FakeProcessManager.any(),
  });
148

149
  testUsingContext('Fails on compilation errors in hot restart', () async {
150 151 152 153 154 155 156 157 158 159 160 161
    final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory);
    final ResidentWebRunner residentWebRunner = ResidentWebRunner(
      mockFlutterDevice,
      flutterProject: project,
      debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
      ipv6: true,
      urlTunneller: null,
      fileSystem: fileSystem,
      logger: BufferLogger.test(),
      systemClock: SystemClock.fixed(DateTime(0, 0, 0)),
      usage: TestUsage(),
    );
162
    final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
163
    unawaited(residentWebRunner.run(
164 165 166 167 168 169 170
      connectionInfoCompleter: connectionInfoCompleter,
    ));
    await connectionInfoCompleter.future;
    final OperationResult result = await residentWebRunner.restart(fullRestart: true);

    expect(result.code, 1);
    expect(result.message, contains('Failed to recompile application.'));
171
  }, overrides: <Type, Generator>{
172 173 174 175
    BuildSystem: () => TestBuildSystem.list(<BuildResult>[
      BuildResult(success: true),
      BuildResult(success: false),
    ]),
176
    FileSystem: () => fileSystem,
177 178
    ProcessManager: () => FakeProcessManager.any(),
  });
179
}
180

181 182 183
class FakeWebDevFS extends Fake implements WebDevFS {
  @override
  List<Uri> get sources => <Uri>[];
184

185 186 187 188 189 190
  @override
  Future<Uri> create() async {
    return Uri.base;
  }
}

191 192 193
// Unfortunately Device, despite not being immutable, has an `operator ==`.
// Until we fix that, we have to also ignore related lints here.
// ignore: avoid_implementing_value_types
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
class FakeWebDevice extends Fake implements Device {
  @override
  String get name => 'web';

  @override
  Future<bool> stopApp(
    covariant ApplicationPackage app, {
    String userIdentifier,
  }) async {
    return true;
  }

  @override
  Future<LaunchResult> startApp(
    covariant ApplicationPackage package, {
    String mainPath,
    String route,
    DebuggingOptions debuggingOptions,
    Map<String, dynamic> platformArgs,
    bool prebuiltApplication = false,
    bool ipv6 = false,
    String userIdentifier,
  }) async {
    return LaunchResult.succeeded();
  }
219 220
}

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
class FakeFlutterDevice extends Fake implements FlutterDevice {
  FakeFlutterDevice(this.device);

  @override
  final FakeWebDevice device;


  DevFS _devFS;

  @override
  DevFS get devFS => _devFS;

  @override
  set devFS(DevFS value) { }

  @override
  FlutterVmService vmService;
}