flutter_tester_device_test.dart 8.53 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2014 The Flutter 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 'package:dds/dds.dart';
8 9
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
10 11
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
12
import 'package:flutter_tools/src/base/platform.dart';
13 14 15
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/test/flutter_tester_device.dart';
16
import 'package:flutter_tools/src/test/font_config_manager.dart';
17
import 'package:stream_channel/stream_channel.dart';
18
import 'package:test/fake.dart';
19 20 21

import '../src/common.dart';
import '../src/context.dart';
22
import '../src/fake_process_manager.dart';
23 24

void main() {
25 26 27 28
  late FakePlatform platform;
  late FileSystem fileSystem;
  late FakeProcessManager processManager;
  late FlutterTesterTestDevice device;
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

  setUp(() {
    fileSystem = MemoryFileSystem.test();
    // Not Windows.
    platform = FakePlatform(
      environment: <String, String>{},
    );
    processManager = FakeProcessManager.any();
  });

  FlutterTesterTestDevice createDevice({
    List<String> dartEntrypointArgs = const <String>[],
    bool enableObservatory = false,
  }) =>
    TestFlutterTesterDevice(
      platform: platform,
      fileSystem: fileSystem,
      processManager: processManager,
      enableObservatory: enableObservatory,
      dartEntrypointArgs: dartEntrypointArgs,
49
      uriConverter: (String input) => '$input/converted',
50 51 52 53
    );

  group('The FLUTTER_TEST environment variable is passed to the test process', () {
    setUp(() {
54
      processManager = FakeProcessManager.list(<FakeCommand>[]);
55 56 57 58 59 60 61 62
      device = createDevice();

      fileSystem
          .file('.dart_tool/package_config.json')
        ..createSync(recursive: true)
        ..writeAsStringSync('{"configVersion":2,"packages":[]}');
    });

63 64 65 66 67 68 69 70 71 72 73 74
    FakeCommand flutterTestCommand(String expectedFlutterTestValue) {
      return FakeCommand(command: const <String>[
        '/',
        '--disable-observatory',
        '--ipv6',
        '--enable-checked-mode',
        '--verify-entry-points',
        '--enable-software-rendering',
        '--skia-deterministic-rendering',
        '--enable-dart-profiling',
        '--non-interactive',
        '--use-test-fonts',
75
        '--disable-asset-fonts',
76
        '--packages=.dart_tool/package_config.json',
77
        'example.dill',
78 79 80
      ], environment: <String, String>{
        'FLUTTER_TEST': expectedFlutterTestValue,
        'FONTCONFIG_FILE': device.fontConfigManager.fontConfigFile.path,
81
        'SERVER_PORT': '0',
82
        'APP_NAME': '',
83 84 85 86
      });
    }

    testUsingContext('as true when not originally set', () async {
87 88
      processManager.addCommand(flutterTestCommand('true'));

89
      await device.start('example.dill');
90
      expect(processManager, hasNoRemainingExpectations);
91 92 93 94
    });

    testUsingContext('as true when set to true', () async {
      platform.environment = <String, String>{'FLUTTER_TEST': 'true'};
95 96
      processManager.addCommand(flutterTestCommand('true'));

97
      await device.start('example.dill');
98
      expect(processManager, hasNoRemainingExpectations);
99 100 101 102
    });

    testUsingContext('as false when set to false', () async {
      platform.environment = <String, String>{'FLUTTER_TEST': 'false'};
103 104
      processManager.addCommand(flutterTestCommand('false'));

105
      await device.start('example.dill');
106
      expect(processManager, hasNoRemainingExpectations);
107 108 109 110
    });

    testUsingContext('unchanged when set', () async {
      platform.environment = <String, String>{'FLUTTER_TEST': 'neither true nor false'};
111 112
      processManager.addCommand(flutterTestCommand('neither true nor false'));

113
      await device.start('example.dill');
114
      expect(processManager, hasNoRemainingExpectations);
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    });
  });

  group('Dart Entrypoint Args', () {
    setUp(() {
      processManager = FakeProcessManager.list(<FakeCommand>[
        const FakeCommand(
          command: <String>[
            '/',
            '--disable-observatory',
            '--ipv6',
            '--enable-checked-mode',
            '--verify-entry-points',
            '--enable-software-rendering',
            '--skia-deterministic-rendering',
            '--enable-dart-profiling',
            '--non-interactive',
            '--use-test-fonts',
133
            '--disable-asset-fonts',
134 135 136
            '--packages=.dart_tool/package_config.json',
            '--foo',
            '--bar',
137
            'example.dill',
138 139 140
          ],
          stdout: 'success',
          stderr: 'failure',
141
        ),
142 143 144 145 146
      ]);
      device = createDevice(dartEntrypointArgs: <String>['--foo', '--bar']);
    });

    testUsingContext('Can pass additional arguments to tester binary', () async {
147
      await device.start('example.dill');
148

149
      expect(processManager, hasNoRemainingExpectations);
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
    });
  });

  group('DDS', () {
    setUp(() {
      processManager = FakeProcessManager.list(<FakeCommand>[
        const FakeCommand(
          command: <String>[
            '/',
            '--observatory-port=0',
            '--ipv6',
            '--enable-checked-mode',
            '--verify-entry-points',
            '--enable-software-rendering',
            '--skia-deterministic-rendering',
            '--enable-dart-profiling',
            '--non-interactive',
            '--use-test-fonts',
168
            '--disable-asset-fonts',
169
            '--packages=.dart_tool/package_config.json',
170
            'example.dill',
171
          ],
172
          stdout: 'The Dart VM service is listening on http://localhost:1234',
173
          stderr: 'failure',
174
        ),
175 176 177 178
      ]);
      device = createDevice(enableObservatory: true);
    });

nt4f04uNd's avatar
nt4f04uNd committed
179
    testUsingContext('skips setting observatory port and uses the input port for DDS instead', () async {
180
      await device.start('example.dill');
181 182 183 184 185
      await device.observatoryUri;

      final Uri uri = await (device as TestFlutterTesterDevice).ddsServiceUriFuture();
      expect(uri.port, 1234);
    });
186 187 188 189 190 191 192 193 194 195 196 197

    testUsingContext('sets up UriConverter from context', () async {
      await device.start('example.dill');
      await device.observatoryUri;

      final FakeDartDevelopmentService dds = (device as TestFlutterTesterDevice).dds
      as FakeDartDevelopmentService;
      final String? result = dds
          .uriConverter
          ?.call('test');
      expect(result, 'test/converted');
    });
198 199 200 201 202 203 204 205
  });
}

/// A Flutter Tester device.
///
/// Uses a mock HttpServer. We don't want to bind random ports in our CI hosts.
class TestFlutterTesterDevice extends FlutterTesterTestDevice {
  TestFlutterTesterDevice({
206 207 208 209 210
    required super.platform,
    required super.fileSystem,
    required super.processManager,
    required super.enableObservatory,
    required List<String> dartEntrypointArgs,
211
    required UriConverter uriConverter,
212 213 214
  }) : super(
    id: 999,
    shellPath: '/',
215
    logger: BufferLogger.test(),
216 217 218 219 220 221 222 223 224 225 226
    debuggingOptions: DebuggingOptions.enabled(
      const BuildInfo(
        BuildMode.debug,
        '',
        treeShakeIcons: false,
      ),
      hostVmServicePort: 1234,
      dartEntrypointArgs: dartEntrypointArgs,
    ),
    machine: false,
    host: InternetAddress.loopbackIPv6,
227
    testAssetDirectory: null,
228 229 230 231
    flutterProject: null,
    icudtlPath: null,
    compileExpression: null,
    fontConfigManager: FontConfigManager(),
232
    uriConverter: uriConverter,
233
  );
234
  late DartDevelopmentService dds;
235 236 237 238 239 240

  final Completer<Uri> _ddsServiceUriCompleter = Completer<Uri>();

  Future<Uri> ddsServiceUriFuture() => _ddsServiceUriCompleter.future;

  @override
241 242 243 244
  Future<DartDevelopmentService> startDds(
    Uri uri, {
    UriConverter? uriConverter,
  }) async {
245
    _ddsServiceUriCompleter.complete(uri);
246 247 248 249 250 251
    dds = FakeDartDevelopmentService(
      Uri.parse('http://localhost:${debuggingOptions.hostVmServicePort}'),
      Uri.parse('http://localhost:8080'),
      uriConverter: uriConverter,
    );
    return dds;
252 253 254
  }

  @override
255
  Future<HttpServer> bind(InternetAddress? host, int port) async => FakeHttpServer();
256 257 258 259 260

  @override
  Future<StreamChannel<String>> get remoteChannel async => StreamChannelController<String>().foreign;
}

261
class FakeDartDevelopmentService extends Fake implements DartDevelopmentService {
262
  FakeDartDevelopmentService(this.uri, this.original, {this.uriConverter});
263 264

  final Uri original;
265
  final UriConverter? uriConverter;
266 267 268 269 270 271 272 273 274 275 276

  @override
  final Uri uri;

  @override
  Uri get remoteVmServiceUri => original;
}
class FakeHttpServer extends Fake implements HttpServer {
  @override
  int get port => 0;
}