// Copyright 2019 The Chromium 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 'package:build_daemon/client.dart'; import 'package:build_daemon/data/build_status.dart'; import 'package:built_collection/built_collection.dart'; import 'package:dwds/asset_handler.dart'; import 'package:dwds/dwds.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/web/chrome.dart'; import 'package:flutter_tools/src/build_runner/web_fs.dart'; import 'package:http_multi_server/http_multi_server.dart'; import 'package:meta/meta.dart'; import 'package:mockito/mockito.dart'; import '../../src/common.dart'; import '../../src/testbed.dart'; void main() { Testbed testbed; MockBuildDaemonCreator mockBuildDaemonCreator; MockDwds mockDwds; MockChromeLauncher mockChromeLauncher; MockHttpMultiServer mockHttpMultiServer; MockBuildDaemonClient mockBuildDaemonClient; MockOperatingSystemUtils mockOperatingSystemUtils; MockProcessUtils mockProcessUtils; bool lastInitializePlatform; dynamic lastAddress; int lastPort; setUp(() { lastAddress = null; lastPort = null; lastInitializePlatform = null; mockBuildDaemonCreator = MockBuildDaemonCreator(); mockChromeLauncher = MockChromeLauncher(); mockHttpMultiServer = MockHttpMultiServer(); mockBuildDaemonClient = MockBuildDaemonClient(); mockOperatingSystemUtils = MockOperatingSystemUtils(); mockDwds = MockDwds(); mockProcessUtils = MockProcessUtils(); when(mockBuildDaemonCreator.startBuildDaemon(any, release: anyNamed('release'), initializePlatform: anyNamed('initializePlatform'))) .thenAnswer((Invocation invocation) async { lastInitializePlatform = invocation.namedArguments[#initializePlatform]; return mockBuildDaemonClient; }); when(mockOperatingSystemUtils.findFreePort()).thenAnswer((Invocation _) async { return 1234; }); when(mockProcessUtils.stream( any, workingDirectory: anyNamed('workingDirectory'), mapFunction: anyNamed('mapFunction'), environment: anyNamed('environment'), )).thenAnswer((Invocation invocation) async { final String workingDirectory = invocation.namedArguments[#workingDirectory]; fs.file(fs.path.join(workingDirectory, '.packages')).createSync(recursive: true); return 0; }); when(mockBuildDaemonClient.buildResults).thenAnswer((Invocation _) { return Stream<BuildResults>.fromFuture(Future<BuildResults>.value( BuildResults((BuildResultsBuilder builder) { builder.results = ListBuilder<BuildResult>( <BuildResult>[ DefaultBuildResult((DefaultBuildResultBuilder builder) { builder.target = 'web'; builder.status = BuildStatus.succeeded; }), ], ); }) )); }); when(mockBuildDaemonCreator.assetServerPort(any)).thenReturn(4321); testbed = Testbed( setup: () { fs.file(fs.path.join('packages', 'flutter_tools', 'pubspec.yaml')) ..createSync(recursive: true) ..setLastModifiedSync(DateTime(1991, 08, 23)); // Create an empty .packages file so we can read it when we check for // plugins on WebFs.start() fs.file('.packages').createSync(); }, overrides: <Type, Generator>{ Pub: () => MockPub(), OperatingSystemUtils: () => mockOperatingSystemUtils, BuildDaemonCreator: () => mockBuildDaemonCreator, ChromeLauncher: () => mockChromeLauncher, ProcessUtils: () => mockProcessUtils, HttpMultiServerFactory: () => (dynamic address, int port) async { lastAddress = address; lastPort = port; return mockHttpMultiServer; }, DwdsFactory: () => ({ @required AssetHandler assetHandler, @required Stream<BuildResult> buildResults, @required ConnectionProvider chromeConnection, String hostname, ReloadConfiguration reloadConfiguration, bool serveDevTools, LogWriter logWriter, bool verbose, bool enableDebugExtension, }) async { return mockDwds; }, }, ); }); test('Can create webFs from mocked interfaces', () => testbed.run(() async { final FlutterProject flutterProject = FlutterProject.current(); await WebFs.start( skipDwds: false, target: fs.path.join('lib', 'main.dart'), buildInfo: BuildInfo.debug, flutterProject: flutterProject, initializePlatform: true, hostname: null, port: null, dartDefines: const <String>[], ); // Since the .packages file is missing in the memory filesystem, this should // be called. verify(pub.get( context: PubContext.pubGet, directory: anyNamed('directory'), offline: true, skipPubspecYamlCheck: true, checkLastModified: false, )).called(1); // The build daemon is told to build once. verify(mockBuildDaemonClient.startBuild()).called(1); // .dart_tool directory is created. expect(flutterProject.dartTool.existsSync(), true); expect(lastInitializePlatform, true); })); test('Can create webFs from mocked interfaces with initializePlatform', () => testbed.run(() async { final FlutterProject flutterProject = FlutterProject.current(); await WebFs.start( skipDwds: false, target: fs.path.join('lib', 'main.dart'), buildInfo: BuildInfo.debug, flutterProject: flutterProject, initializePlatform: false, hostname: null, port: null, dartDefines: const <String>[], ); // The build daemon is told to build once. verify(mockBuildDaemonClient.startBuild()).called(1); // .dart_tool directory is created. expect(flutterProject.dartTool.existsSync(), true); expect(lastInitializePlatform, false); })); test('Uses provided port number and hostname.', () => testbed.run(() async { final FlutterProject flutterProject = FlutterProject.current(); final WebFs webFs = await WebFs.start( skipDwds: false, target: fs.path.join('lib', 'main.dart'), buildInfo: BuildInfo.debug, flutterProject: flutterProject, initializePlatform: false, hostname: 'foo', port: '1234', dartDefines: const <String>[], ); expect(webFs.uri, contains('foo:1234')); expect(lastPort, 1234); expect(lastAddress, contains('foo')); })); test('Throws exception if build fails', () => testbed.run(() async { when(mockBuildDaemonClient.buildResults).thenAnswer((Invocation _) { return Stream<BuildResults>.fromFuture(Future<BuildResults>.value( BuildResults((BuildResultsBuilder builder) { builder.results = ListBuilder<BuildResult>( <BuildResult>[ DefaultBuildResult((DefaultBuildResultBuilder builder) { builder.target = 'web'; builder.status = BuildStatus.failed; }), ], ); }) )); }); final FlutterProject flutterProject = FlutterProject.current(); expect(WebFs.start( skipDwds: false, target: fs.path.join('lib', 'main.dart'), buildInfo: BuildInfo.debug, flutterProject: flutterProject, initializePlatform: false, hostname: 'foo', port: '1234', dartDefines: const <String>[], ), throwsA(isInstanceOf<Exception>())); })); } class MockBuildDaemonCreator extends Mock implements BuildDaemonCreator {} class MockBuildDaemonClient extends Mock implements BuildDaemonClient {} class MockDwds extends Mock implements Dwds {} class MockHttpMultiServer extends Mock implements HttpMultiServer {} class MockChromeLauncher extends Mock implements ChromeLauncher {} class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {} class MockProcessUtils extends Mock implements ProcessUtils {} class MockPub extends Mock implements Pub {}