fuchsia_device_start_test.dart 24.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// 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 'dart:convert';

import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/os.dart';
13
import 'package:flutter_tools/src/base/platform.dart';
14 15 16 17 18 19 20 21
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/fuchsia/application_package.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_device.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_ffx.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_kernel_compiler.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_pm.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart';
22
import 'package:flutter_tools/src/fuchsia/pkgctl.dart';
23
import 'package:flutter_tools/src/globals.dart' as globals;
24
import 'package:flutter_tools/src/project.dart';
25
import 'package:test/fake.dart';
26 27 28 29 30 31 32

import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';

void main() {
  group('Fuchsia app start and stop: ', () {
33 34 35 36 37 38 39 40
    late MemoryFileSystem memoryFileSystem;
    late FakeOperatingSystemUtils osUtils;
    late FakeFuchsiaDeviceTools fuchsiaDeviceTools;
    late FakeFuchsiaSdk fuchsiaSdk;
    late Artifacts artifacts;
    late FakeProcessManager fakeSuccessfulProcessManager;
    late FakeProcessManager fakeFailedProcessManagerForHostAddress;
    late File sshConfig;
41 42 43 44 45

    setUp(() {
      memoryFileSystem = MemoryFileSystem.test();
      osUtils = FakeOperatingSystemUtils();
      fuchsiaDeviceTools = FakeFuchsiaDeviceTools();
46
      fuchsiaSdk = FakeFuchsiaSdk();
47 48
      sshConfig = MemoryFileSystem.test().file('ssh_config')
        ..writeAsStringSync('\n');
49
      artifacts = Artifacts.test();
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
      for (final BuildMode mode in <BuildMode>[
        BuildMode.debug,
        BuildMode.release
      ]) {
        memoryFileSystem
            .file(
              artifacts.getArtifactPath(Artifact.fuchsiaKernelCompiler,
                  platform: TargetPlatform.fuchsia_arm64, mode: mode),
            )
            .createSync();

        memoryFileSystem
            .file(
              artifacts.getArtifactPath(Artifact.platformKernelDill,
                  platform: TargetPlatform.fuchsia_arm64, mode: mode),
            )
            .createSync();

        memoryFileSystem
            .file(
              artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath,
                  platform: TargetPlatform.fuchsia_arm64, mode: mode),
            )
            .createSync();

        memoryFileSystem
            .file(
              artifacts.getArtifactPath(Artifact.fuchsiaFlutterRunner,
                  platform: TargetPlatform.fuchsia_arm64, mode: mode),
            )
            .createSync();
81 82 83
      }
      fakeSuccessfulProcessManager = FakeProcessManager.list(<FakeCommand>[
        FakeCommand(
84 85 86 87 88 89 90 91 92
          command: <String>[
            'ssh',
            '-F',
            sshConfig.absolute.path,
            '123',
            r'echo $SSH_CONNECTION'
          ],
          stdout:
              'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22',
93 94
        ),
      ]);
95 96
      fakeFailedProcessManagerForHostAddress =
          FakeProcessManager.list(<FakeCommand>[
97
        FakeCommand(
98 99 100 101 102 103 104 105 106
          command: <String>[
            'ssh',
            '-F',
            sshConfig.absolute.path,
            '123',
            r'echo $SSH_CONNECTION'
          ],
          stdout:
              'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22',
107 108 109 110 111 112
          exitCode: 1,
        ),
      ]);
    });

    Future<LaunchResult> setupAndStartApp({
113 114
      required bool prebuilt,
      required BuildMode mode,
115 116 117 118 119 120 121
    }) async {
      const String appName = 'app_name';
      final FuchsiaDevice device = FuchsiaDeviceWithFakeDiscovery('123');
      globals.fs.directory('fuchsia').createSync(recursive: true);
      final File pubspecFile = globals.fs.file('pubspec.yaml')..createSync();
      pubspecFile.writeAsStringSync('name: $appName');

122
      FuchsiaApp? app;
123 124 125 126
      if (prebuilt) {
        final File far = globals.fs.file('app_name-0.far')..createSync();
        app = FuchsiaApp.fromPrebuiltApp(far);
      } else {
127
        globals.fs.file(globals.fs.path.join('fuchsia', 'meta', '$appName.cm'))
128 129 130
          ..createSync(recursive: true)
          ..writeAsStringSync('{}');
        globals.fs.file('.packages').createSync();
131 132 133 134 135 136 137
        globals.fs
            .file(globals.fs.path.join('lib', 'main.dart'))
            .createSync(recursive: true);
        app = BuildableFuchsiaApp(
            project:
                FlutterProject.fromDirectoryTest(globals.fs.currentDirectory)
                    .fuchsia);
138 139
      }

140 141
      final DebuggingOptions debuggingOptions = DebuggingOptions.disabled(
          BuildInfo(mode, null, treeShakeIcons: false));
142
      return device.startApp(
143
        app!,
144 145 146 147 148
        prebuiltApplication: prebuilt,
        debuggingOptions: debuggingOptions,
      );
    }

149 150 151
    testUsingContext(
        'start prebuilt in release mode fails without session',
        () async {
152 153
      final LaunchResult launchResult =
          await setupAndStartApp(prebuilt: true, mode: BuildMode.release);
154
      expect(launchResult.started, isFalse);
155
      expect(launchResult.hasVmService, isFalse);
156 157 158 159 160 161 162 163 164 165
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
      ProcessManager: () => fakeSuccessfulProcessManager,
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
      FuchsiaSdk: () => fuchsiaSdk,
      OperatingSystemUtils: () => osUtils,
    });

166 167
    testUsingContext('start prebuilt in release mode with session', () async {
      final LaunchResult launchResult =
168
          await setupAndStartApp(prebuilt: true, mode: BuildMode.release);
169
      expect(launchResult.started, isTrue);
170
      expect(launchResult.hasVmService, isFalse);
171 172 173
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
174
      ProcessManager: () => fakeSuccessfulProcessManager,
175 176
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
177
      FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()),
178 179 180
      OperatingSystemUtils: () => osUtils,
    });

181 182 183
    testUsingContext(
        'start and stop prebuilt in release mode fails without session',
        () async {
184 185 186 187 188 189 190
      const String appName = 'app_name';
      final FuchsiaDevice device = FuchsiaDeviceWithFakeDiscovery('123');
      globals.fs.directory('fuchsia').createSync(recursive: true);
      final File pubspecFile = globals.fs.file('pubspec.yaml')..createSync();
      pubspecFile.writeAsStringSync('name: $appName');
      final File far = globals.fs.file('app_name-0.far')..createSync();

191
      final FuchsiaApp app = FuchsiaApp.fromPrebuiltApp(far)!;
192 193
      final DebuggingOptions debuggingOptions = DebuggingOptions.disabled(
          const BuildInfo(BuildMode.release, null, treeShakeIcons: false));
194
      final LaunchResult launchResult = await device.startApp(app,
195 196
          prebuiltApplication: true, debuggingOptions: debuggingOptions);
      expect(launchResult.started, isFalse);
197
      expect(launchResult.hasVmService, isFalse);
198 199 200 201 202 203 204 205 206 207
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
      ProcessManager: () => fakeSuccessfulProcessManager,
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
      FuchsiaSdk: () => fuchsiaSdk,
      OperatingSystemUtils: () => osUtils,
    });

208 209
    testUsingContext('start and stop prebuilt in release mode with session',
        () async {
210 211 212 213 214 215 216
      const String appName = 'app_name';
      final FuchsiaDevice device = FuchsiaDeviceWithFakeDiscovery('123');
      globals.fs.directory('fuchsia').createSync(recursive: true);
      final File pubspecFile = globals.fs.file('pubspec.yaml')..createSync();
      pubspecFile.writeAsStringSync('name: $appName');
      final File far = globals.fs.file('app_name-0.far')..createSync();

217
      final FuchsiaApp app = FuchsiaApp.fromPrebuiltApp(far)!;
218 219
      final DebuggingOptions debuggingOptions = DebuggingOptions.disabled(
          const BuildInfo(BuildMode.release, null, treeShakeIcons: false));
220
      final LaunchResult launchResult = await device.startApp(app,
221
          prebuiltApplication: true, debuggingOptions: debuggingOptions);
222
      expect(launchResult.started, isTrue);
223
      expect(launchResult.hasVmService, isFalse);
224 225 226 227
      expect(await device.stopApp(app), isTrue);
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
228
      ProcessManager: () => fakeSuccessfulProcessManager,
229 230
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
231
      FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()),
232 233 234
      OperatingSystemUtils: () => osUtils,
    });

235 236 237
    testUsingContext(
        'start prebuilt in debug mode fails without session',
        () async {
238 239
      final LaunchResult launchResult =
          await setupAndStartApp(prebuilt: true, mode: BuildMode.debug);
240
      expect(launchResult.started, isFalse);
241 242 243 244 245 246 247 248 249 250
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
      ProcessManager: () => fakeSuccessfulProcessManager,
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
      FuchsiaSdk: () => fuchsiaSdk,
      OperatingSystemUtils: () => osUtils,
    });

251 252
    testUsingContext('start prebuilt in debug mode with session', () async {
      final LaunchResult launchResult =
253
          await setupAndStartApp(prebuilt: true, mode: BuildMode.debug);
254
      expect(launchResult.started, isTrue);
255
      expect(launchResult.hasVmService, isTrue);
256 257 258
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
259
      ProcessManager: () => fakeSuccessfulProcessManager,
260 261
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
262
      FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()),
263 264 265
      OperatingSystemUtils: () => osUtils,
    });

266 267 268 269 270 271 272 273 274
    testUsingContext(
        'start buildable in release mode fails without session',
        () async {
      expect(
          () async => setupAndStartApp(prebuilt: false, mode: BuildMode.release),
          throwsToolExit(
              message: 'This tool does not currently build apps for fuchsia.\n'
                  'Build the app using a supported Fuchsia workflow.\n'
                  'Then use the --use-application-binary flag.'));
275 276 277 278 279 280 281 282 283 284
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
      ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
            const FakeCommand(
              command: <String>[
                'Artifact.genSnapshot.TargetPlatform.fuchsia_arm64.release',
                '--deterministic',
                '--snapshot_kind=app-aot-elf',
                '--elf=build/fuchsia/elf.aotsnapshot',
285
                'build/fuchsia/app_name.dil',
286 287 288
              ],
            ),
            FakeCommand(
289 290 291 292 293 294 295 296 297
              command: <String>[
                'ssh',
                '-F',
                sshConfig.absolute.path,
                '123',
                r'echo $SSH_CONNECTION'
              ],
              stdout:
                  'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22',
298 299 300 301 302 303 304 305
            ),
          ]),
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
      FuchsiaSdk: () => fuchsiaSdk,
      OperatingSystemUtils: () => osUtils,
    });

306 307 308 309 310 311 312 313 314
    testUsingContext(
        'start buildable in release mode with session fails, does not build apps yet',
        () async {
      expect(
          () async => setupAndStartApp(prebuilt: false, mode: BuildMode.release),
          throwsToolExit(
              message: 'This tool does not currently build apps for fuchsia.\n'
                  'Build the app using a supported Fuchsia workflow.\n'
                  'Then use the --use-application-binary flag.'));
315 316 317 318
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
      ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
            const FakeCommand(
              command: <String>[
                'Artifact.genSnapshot.TargetPlatform.fuchsia_arm64.release',
                '--deterministic',
                '--snapshot_kind=app-aot-elf',
                '--elf=build/fuchsia/elf.aotsnapshot',
                'build/fuchsia/app_name.dil',
              ],
            ),
            FakeCommand(
              command: <String>[
                'ssh',
                '-F',
                sshConfig.absolute.path,
                '123',
                r'echo $SSH_CONNECTION'
              ],
              stdout:
                  'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22',
            ),
          ]),
340 341
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
342
      FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()),
343 344 345
      OperatingSystemUtils: () => osUtils,
    });

346 347 348 349 350 351 352 353 354
    testUsingContext(
        'start buildable in debug mode fails without session',
        () async {
      expect(
          () async => setupAndStartApp(prebuilt: false, mode: BuildMode.debug),
          throwsToolExit(
              message: 'This tool does not currently build apps for fuchsia.\n'
                  'Build the app using a supported Fuchsia workflow.\n'
                  'Then use the --use-application-binary flag.'));
355 356 357 358 359 360 361 362 363 364
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
      ProcessManager: () => fakeSuccessfulProcessManager,
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
      FuchsiaSdk: () => fuchsiaSdk,
      OperatingSystemUtils: () => osUtils,
    });

365 366 367 368 369 370 371 372 373
    testUsingContext(
        'start buildable in debug mode with session fails, does not build apps yet',
        () async {
      expect(
          () async => setupAndStartApp(prebuilt: false, mode: BuildMode.debug),
          throwsToolExit(
              message: 'This tool does not currently build apps for fuchsia.\n'
                  'Build the app using a supported Fuchsia workflow.\n'
                  'Then use the --use-application-binary flag.'));
374 375 376
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
377
      ProcessManager: () => fakeSuccessfulProcessManager,
378 379
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
380
      FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()),
381 382 383
      OperatingSystemUtils: () => osUtils,
    });

384
    testUsingContext('fail when cant get ssh config', () async {
385 386 387 388 389
      expect(
          () async => setupAndStartApp(prebuilt: true, mode: BuildMode.release),
          throwsToolExit(
              message: 'Cannot interact with device. No ssh config.\n'
                  'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.'));
390 391 392 393
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
      ProcessManager: () => FakeProcessManager.any(),
394
      FuchsiaArtifacts: () => FuchsiaArtifacts(),
395
      FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()),
396 397 398 399
      OperatingSystemUtils: () => osUtils,
    });

    testUsingContext('fail when cant get host address', () async {
400
      expect(() async => FuchsiaDeviceWithFakeDiscovery('123').hostAddress,
401 402 403 404
          throwsToolExit(message: 'Failed to get local address, aborting.'));
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
405
      ProcessManager: () => fakeFailedProcessManagerForHostAddress,
406 407 408
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
      OperatingSystemUtils: () => osUtils,
409
      Platform: () => FakePlatform(),
410 411 412 413 414 415
    });

    testUsingContext('fail with correct LaunchResult when pm fails', () async {
      final LaunchResult launchResult =
          await setupAndStartApp(prebuilt: true, mode: BuildMode.release);
      expect(launchResult.started, isFalse);
416
      expect(launchResult.hasVmService, isFalse);
417 418 419 420 421 422
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
      ProcessManager: () => fakeSuccessfulProcessManager,
      FuchsiaDeviceTools: () => fuchsiaDeviceTools,
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
423
      FuchsiaSdk: () => FakeFuchsiaSdk(pm: FailingPM()),
424 425 426
      OperatingSystemUtils: () => osUtils,
    });

427 428
    testUsingContext('fail with correct LaunchResult when pkgctl fails',
        () async {
429 430 431
      final LaunchResult launchResult =
          await setupAndStartApp(prebuilt: true, mode: BuildMode.release);
      expect(launchResult.started, isFalse);
432
      expect(launchResult.hasVmService, isFalse);
433 434 435 436
    }, overrides: <Type, Generator>{
      Artifacts: () => artifacts,
      FileSystem: () => memoryFileSystem,
      ProcessManager: () => fakeSuccessfulProcessManager,
437
      FuchsiaDeviceTools: () => FakeFuchsiaDeviceTools(pkgctl: FailingPkgctl()),
438 439 440 441 442 443 444
      FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
      FuchsiaSdk: () => fuchsiaSdk,
      OperatingSystemUtils: () => osUtils,
    });
  });
}

445
Process _createFakeProcess({
446 447 448 449 450
  int exitCode = 0,
  String stdout = '',
  String stderr = '',
  bool persistent = false,
}) {
451 452
  final Stream<List<int>> stdoutStream =
      Stream<List<int>>.fromIterable(<List<int>>[
453 454
    utf8.encode(stdout),
  ]);
455 456
  final Stream<List<int>> stderrStream =
      Stream<List<int>>.fromIterable(<List<int>>[
457 458
    utf8.encode(stderr),
  ]);
459 460 461 462
  final Completer<int> exitCodeCompleter = Completer<int>();
  final Process process = FakeProcess(
    stdout: stdoutStream,
    stderr: stderrStream,
463 464
    exitCode:
        persistent ? exitCodeCompleter.future : Future<int>.value(exitCode),
465
  );
466 467 468 469
  return process;
}

class FuchsiaDeviceWithFakeDiscovery extends FuchsiaDevice {
470
  FuchsiaDeviceWithFakeDiscovery(super.id, {super.name = ''});
471 472

  @override
473 474
  FuchsiaIsolateDiscoveryProtocol getIsolateDiscoveryProtocol(
      String isolateName) {
475 476 477 478
    return FakeFuchsiaIsolateDiscoveryProtocol();
  }

  @override
479 480
  Future<TargetPlatform> get targetPlatform async =>
      TargetPlatform.fuchsia_arm64;
481 482
}

483 484
class FakeFuchsiaIsolateDiscoveryProtocol
    implements FuchsiaIsolateDiscoveryProtocol {
485 486 487 488 489 490 491
  @override
  FutureOr<Uri> get uri => Uri.parse('http://[::1]:37');

  @override
  void dispose() {}
}

492
class FakeFuchsiaPkgctl implements FuchsiaPkgctl {
493
  @override
494 495
  Future<bool> addRepo(
      FuchsiaDevice device, FuchsiaPackageServer server) async {
496 497 498 499
    return true;
  }

  @override
500 501
  Future<bool> resolve(
      FuchsiaDevice device, String serverName, String packageName) async {
502 503 504 505
    return true;
  }

  @override
506
  Future<bool> rmRepo(FuchsiaDevice device, FuchsiaPackageServer server) async {
507 508 509 510
    return true;
  }
}

511
class FailingPkgctl implements FuchsiaPkgctl {
512
  @override
513 514
  Future<bool> addRepo(
      FuchsiaDevice device, FuchsiaPackageServer server) async {
515 516 517 518
    return false;
  }

  @override
519 520
  Future<bool> resolve(
      FuchsiaDevice device, String serverName, String packageName) async {
521 522 523 524
    return false;
  }

  @override
525
  Future<bool> rmRepo(FuchsiaDevice device, FuchsiaPackageServer server) async {
526 527 528 529 530 531
    return false;
  }
}

class FakeFuchsiaDeviceTools implements FuchsiaDeviceTools {
  FakeFuchsiaDeviceTools({
532 533
    FuchsiaPkgctl? pkgctl,
    FuchsiaFfx? ffx,
534
  })  : pkgctl = pkgctl ?? FakeFuchsiaPkgctl(),
535
        ffx = ffx ?? FakeFuchsiaFfx();
536 537

  @override
538
  final FuchsiaPkgctl pkgctl;
539 540

  @override
541
  final FuchsiaFfx ffx;
542 543 544
}

class FakeFuchsiaPM implements FuchsiaPM {
545
  String? _appName;
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560

  @override
  Future<bool> init(String buildPath, String appName) async {
    if (!globals.fs.directory(buildPath).existsSync()) {
      return false;
    }
    globals.fs
        .file(globals.fs.path.join(buildPath, 'meta', 'package'))
        .createSync(recursive: true);
    _appName = appName;
    return true;
  }

  @override
  Future<bool> build(String buildPath, String manifestPath) async {
561 562 563
    if (!globals.fs
            .file(globals.fs.path.join(buildPath, 'meta', 'package'))
            .existsSync() ||
564 565 566
        !globals.fs.file(manifestPath).existsSync()) {
      return false;
    }
567 568 569
    globals.fs
        .file(globals.fs.path.join(buildPath, 'meta.far'))
        .createSync(recursive: true);
570 571 572 573 574
    return true;
  }

  @override
  Future<bool> archive(String buildPath, String manifestPath) async {
575 576 577
    if (!globals.fs
            .file(globals.fs.path.join(buildPath, 'meta', 'package'))
            .existsSync() ||
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
        !globals.fs.file(manifestPath).existsSync()) {
      return false;
    }
    if (_appName == null) {
      return false;
    }
    globals.fs
        .file(globals.fs.path.join(buildPath, '$_appName-0.far'))
        .createSync(recursive: true);
    return true;
  }

  @override
  Future<bool> newrepo(String repoPath) async {
    if (!globals.fs.directory(repoPath).existsSync()) {
      return false;
    }
    return true;
  }

  @override
  Future<Process> serve(String repoPath, String host, int port) async {
600
    return _createFakeProcess(persistent: true);
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
  }

  @override
  Future<bool> publish(String repoPath, String packagePath) async {
    if (!globals.fs.directory(repoPath).existsSync()) {
      return false;
    }
    if (!globals.fs.file(packagePath).existsSync()) {
      return false;
    }
    return true;
  }
}

class FailingPM implements FuchsiaPM {
  @override
  Future<bool> init(String buildPath, String appName) async {
    return false;
  }

  @override
  Future<bool> build(String buildPath, String manifestPath) async {
    return false;
  }

  @override
  Future<bool> archive(String buildPath, String manifestPath) async {
    return false;
  }

  @override
  Future<bool> newrepo(String repoPath) async {
    return false;
  }

  @override
  Future<Process> serve(String repoPath, String host, int port) async {
638
    return _createFakeProcess(exitCode: 6);
639 640 641 642 643 644 645 646 647 648 649
  }

  @override
  Future<bool> publish(String repoPath, String packagePath) async {
    return false;
  }
}

class FakeFuchsiaKernelCompiler implements FuchsiaKernelCompiler {
  @override
  Future<void> build({
650 651
    required FuchsiaProject fuchsiaProject,
    required String target, // E.g., lib/main.dart
652 653 654 655
    BuildInfo buildInfo = BuildInfo.debug,
  }) async {
    final String outDir = getFuchsiaBuildDirectory();
    final String appName = fuchsiaProject.project.manifest.appName;
656 657
    final String manifestPath =
        globals.fs.path.join(outDir, '$appName.dilpmanifest');
658 659 660 661 662 663
    globals.fs.file(manifestPath).createSync(recursive: true);
  }
}

class FakeFuchsiaFfx implements FuchsiaFfx {
  @override
664
  Future<List<String>> list({Duration? timeout}) async {
665 666 667 668 669 670 671
    return <String>['192.168.42.172 scare-cable-skip-ffx'];
  }

  @override
  Future<String> resolve(String deviceName) async {
    return '192.168.42.10';
  }
672 673

  @override
674
  Future<String?> sessionShow() async {
675 676 677 678 679 680 681 682 683 684 685
    return null;
  }

  @override
  Future<bool> sessionAdd(String url) async {
    return false;
  }
}

class FakeFuchsiaFfxWithSession implements FuchsiaFfx {
  @override
686
  Future<List<String>> list({Duration? timeout}) async {
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
    return <String>['192.168.42.172 scare-cable-skip-ffx'];
  }

  @override
  Future<String> resolve(String deviceName) async {
    return '192.168.42.10';
  }

  @override
  Future<String> sessionShow() async {
    return 'session info';
  }

  @override
  Future<bool> sessionAdd(String url) async {
    return true;
  }
704 705
}

706 707
class FakeFuchsiaSdk extends Fake implements FuchsiaSdk {
  FakeFuchsiaSdk({
708 709 710
    FuchsiaPM? pm,
    FuchsiaKernelCompiler? compiler,
    FuchsiaFfx? ffx,
711 712 713
  })  : fuchsiaPM = pm ?? FakeFuchsiaPM(),
        fuchsiaKernelCompiler = compiler ?? FakeFuchsiaKernelCompiler(),
        fuchsiaFfx = ffx ?? FakeFuchsiaFfx();
714 715 716 717 718 719 720 721 722 723

  @override
  final FuchsiaPM fuchsiaPM;

  @override
  final FuchsiaKernelCompiler fuchsiaKernelCompiler;

  @override
  final FuchsiaFfx fuchsiaFfx;
}