Revert "Add an option for flutter daemon to listen on a TCP port (#95418)" (#95686)

This reverts commit 2b46ea447fc1d692752ba297722a45143385f30a.
diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart
index f93d73c..39d98c2 100644
--- a/packages/flutter_tools/lib/src/commands/attach.dart
+++ b/packages/flutter_tools/lib/src/commands/attach.dart
@@ -18,7 +18,6 @@
 import  '../build_info.dart';
 import '../commands/daemon.dart';
 import '../compile.dart';
-import '../daemon.dart';
 import '../device.dart';
 import '../device_port_forwarder.dart';
 import '../fuchsia/fuchsia_device.dart';
@@ -236,10 +235,8 @@
 
     final Daemon daemon = boolArg('machine')
       ? Daemon(
-          DaemonConnection(
-            daemonStreams: StdioDaemonStreams(globals.stdio),
-            logger: globals.logger,
-          ),
+          stdinCommandStream,
+          stdoutCommandResponse,
           notifyingLogger: (globals.logger is NotifyingLogger)
             ? globals.logger as NotifyingLogger
             : NotifyingLogger(verbose: globals.logger.isVerbose, parent: globals.logger),
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index cfaa273..3a10b6a 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -18,7 +18,7 @@
 import '../base/terminal.dart';
 import '../base/utils.dart';
 import '../build_info.dart';
-import '../daemon.dart';
+import '../convert.dart';
 import '../device.dart';
 import '../device_port_forwarder.dart';
 import '../emulator.dart';
@@ -41,13 +41,7 @@
 /// It can be shutdown with a `daemon.shutdown` command (or by killing the
 /// process).
 class DaemonCommand extends FlutterCommand {
-  DaemonCommand({ this.hidden = false }) {
-    argParser.addOption(
-      'listen-on-tcp-port',
-      help: 'If specified, the daemon will be listening for commands on the specified port instead of stdio.',
-      valueHelp: 'port',
-    );
-  }
+  DaemonCommand({ this.hidden = false });
 
   @override
   final String name = 'daemon';
@@ -63,31 +57,9 @@
 
   @override
   Future<FlutterCommandResult> runCommand() async {
-    if (argResults['listen-on-tcp-port'] != null) {
-      int port;
-      try {
-        port = int.parse(stringArg('listen-on-tcp-port'));
-      } on FormatException catch (error) {
-        throwToolExit('Invalid port for `--listen-on-tcp-port`: $error');
-      }
-
-      await _DaemonServer(
-        port: port,
-        logger: StdoutLogger(
-          terminal: globals.terminal,
-          stdio: globals.stdio,
-          outputPreferences: globals.outputPreferences,
-        ),
-        notifyingLogger: asLogger<NotifyingLogger>(globals.logger),
-      ).run();
-      return FlutterCommandResult.success();
-    }
     globals.printStatus('Starting device daemon...');
     final Daemon daemon = Daemon(
-      DaemonConnection(
-        daemonStreams: StdioDaemonStreams(globals.stdio),
-        logger: globals.logger,
-      ),
+      stdinCommandStream, stdoutCommandResponse,
       notifyingLogger: asLogger<NotifyingLogger>(globals.logger),
     );
     final int code = await daemon.onExit;
@@ -98,57 +70,14 @@
   }
 }
 
-class _DaemonServer {
-  _DaemonServer({
-    this.port,
-    this.logger,
-    this.notifyingLogger,
-  });
-
-  final int port;
-
-  /// Stdout logger used to print general server-related errors.
-  final Logger logger;
-
-  // Logger that sends the message to the other end of daemon connection.
-  final NotifyingLogger notifyingLogger;
-
-  Future<void> run() async {
-    final ServerSocket serverSocket = await ServerSocket.bind(InternetAddress.loopbackIPv4, port);
-    logger.printStatus('Daemon server listening on ${serverSocket.port}');
-
-    final StreamSubscription<Socket> subscription = serverSocket.listen(
-      (Socket socket) async {
-        // We have to listen to socket.done. Otherwise when the connection is
-        // reset, we will receive an uncatchable exception.
-        // https://github.com/dart-lang/sdk/issues/25518
-        final Future<void> socketDone = socket.done.catchError((dynamic error, StackTrace stackTrace) {
-          logger.printError('Socket error: $error');
-          logger.printTrace('$stackTrace');
-        });
-        final Daemon daemon = Daemon(
-          DaemonConnection(
-            daemonStreams: TcpDaemonStreams(socket, logger: logger),
-            logger: logger,
-          ),
-          notifyingLogger: notifyingLogger,
-        );
-        await daemon.onExit;
-        await socketDone;
-      },
-    );
-
-    // Wait indefinitely until the server closes.
-    await subscription.asFuture<void>();
-    await subscription.cancel();
-  }
-}
+typedef DispatchCommand = void Function(Map<String, dynamic> command);
 
 typedef CommandHandler = Future<dynamic> Function(Map<String, dynamic> args);
 
 class Daemon {
   Daemon(
-    this.connection, {
+    Stream<Map<String, dynamic>> commandStream,
+    this.sendCommand, {
     this.notifyingLogger,
     this.logToStdout = false,
   }) {
@@ -160,10 +89,9 @@
     _registerDomain(devToolsDomain = DevToolsDomain(this));
 
     // Start listening.
-    _commandSubscription = connection.incomingCommands.listen(
+    _commandSubscription = commandStream.listen(
       _handleRequest,
       onDone: () {
-        shutdown();
         if (!_onExitCompleter.isCompleted) {
           _onExitCompleter.complete(0);
         }
@@ -171,15 +99,16 @@
     );
   }
 
-  final DaemonConnection connection;
-
   DaemonDomain daemonDomain;
   AppDomain appDomain;
   DeviceDomain deviceDomain;
   EmulatorDomain emulatorDomain;
   DevToolsDomain devToolsDomain;
   StreamSubscription<Map<String, dynamic>> _commandSubscription;
+  int _outgoingRequestId = 1;
+  final Map<String, Completer<dynamic>> _outgoingRequestCompleters = <String, Completer<dynamic>>{};
 
+  final DispatchCommand sendCommand;
   final NotifyingLogger notifyingLogger;
   final bool logToStdout;
 
@@ -205,27 +134,62 @@
 
     try {
       final String method = request['method'] as String;
-      assert(method != null);
-      if (!method.contains('.')) {
-        throw 'method not understood: $method';
-      }
+      if (method != null) {
+        if (!method.contains('.')) {
+          throw 'method not understood: $method';
+        }
 
-      final String prefix = method.substring(0, method.indexOf('.'));
-      final String name = method.substring(method.indexOf('.') + 1);
-      if (_domainMap[prefix] == null) {
-        throw 'no domain for method: $method';
-      }
+        final String prefix = method.substring(0, method.indexOf('.'));
+        final String name = method.substring(method.indexOf('.') + 1);
+        if (_domainMap[prefix] == null) {
+          throw 'no domain for method: $method';
+        }
 
-      _domainMap[prefix].handleCommand(name, id, castStringKeyedMap(request['params']) ?? const <String, dynamic>{});
+        _domainMap[prefix].handleCommand(name, id, castStringKeyedMap(request['params']) ?? const <String, dynamic>{});
+      } else {
+        // If there was no 'method' field then it's a response to a daemon-to-editor request.
+        final Completer<dynamic> completer = _outgoingRequestCompleters[id.toString()];
+        if (completer == null) {
+          throw 'unexpected response with id: $id';
+        }
+        _outgoingRequestCompleters.remove(id.toString());
+
+        if (request['error'] != null) {
+          completer.completeError(request['error']);
+        } else {
+          completer.complete(request['result']);
+        }
+      }
     } on Exception catch (error, trace) {
-      connection.sendErrorResponse(id, _toJsonable(error), trace);
+      _send(<String, dynamic>{
+        'id': id,
+        'error': _toJsonable(error),
+        'trace': '$trace',
+      });
     }
   }
 
+  Future<dynamic> sendRequest(String method, [ dynamic args ]) {
+    final Map<String, dynamic> map = <String, dynamic>{'method': method};
+    if (args != null) {
+      map['params'] = _toJsonable(args);
+    }
+
+    final int id = _outgoingRequestId++;
+    final Completer<dynamic> completer = Completer<dynamic>();
+
+    map['id'] = id.toString();
+    _outgoingRequestCompleters[id.toString()] = completer;
+
+    _send(map);
+    return completer.future;
+  }
+
+  void _send(Map<String, dynamic> map) => sendCommand(map);
+
   Future<void> shutdown({ dynamic error }) async {
     await devToolsDomain?.dispose();
     await _commandSubscription?.cancel();
-    await connection.dispose();
     for (final Domain domain in _domainMap.values) {
       await domain.dispose();
     }
@@ -261,16 +225,30 @@
       }
       throw 'command not understood: $name.$command';
     }).then<dynamic>((dynamic result) {
-      daemon.connection.sendResponse(id, _toJsonable(result));
-    }).catchError((Object error, StackTrace stackTrace) {
-      daemon.connection.sendErrorResponse(id, _toJsonable(error), stackTrace);
+      if (result == null) {
+        _send(<String, dynamic>{'id': id});
+      } else {
+        _send(<String, dynamic>{'id': id, 'result': _toJsonable(result)});
+      }
+    }).catchError((dynamic error, dynamic trace) {
+      _send(<String, dynamic>{
+        'id': id,
+        'error': _toJsonable(error),
+        'trace': '$trace',
+      });
     });
   }
 
   void sendEvent(String name, [ dynamic args ]) {
-    daemon.connection.sendEvent(name, _toJsonable(args));
+    final Map<String, dynamic> map = <String, dynamic>{'event': name};
+    if (args != null) {
+      map['params'] = _toJsonable(args);
+    }
+    _send(map);
   }
 
+  void _send(Map<String, dynamic> map) => daemon._send(map);
+
   String _getStringArg(Map<String, dynamic> args, String name, { bool required = false }) {
     if (required && !args.containsKey(name)) {
       throw '$name is required';
@@ -368,7 +346,7 @@
   /// --web-allow-expose-url switch. The client may return the same URL back if
   /// tunnelling is not required for a given URL.
   Future<String> exposeUrl(String url) async {
-    final dynamic res = await daemon.connection.sendRequest('app.exposeUrl', <String, String>{'url': url});
+    final dynamic res = await daemon.sendRequest('app.exposeUrl', <String, String>{'url': url});
     if (res is Map<String, dynamic> && res['url'] is String) {
       return res['url'] as String;
     } else {
@@ -929,6 +907,35 @@
   }
 }
 
+Stream<Map<String, dynamic>> get stdinCommandStream => globals.stdio.stdin
+  .transform<String>(utf8.decoder)
+  .transform<String>(const LineSplitter())
+  .where((String line) => line.startsWith('[{') && line.endsWith('}]'))
+  .map<Map<String, dynamic>>((String line) {
+    line = line.substring(1, line.length - 1);
+    return castStringKeyedMap(json.decode(line));
+  });
+
+void stdoutCommandResponse(Map<String, dynamic> command) {
+  globals.stdio.stdoutWrite(
+    '[${jsonEncodeObject(command)}]\n',
+    fallback: (String message, dynamic error, StackTrace stack) {
+      throwToolExit('Failed to write daemon command response to stdout: $error');
+    },
+  );
+}
+
+String jsonEncodeObject(dynamic object) {
+  return json.encode(object, toEncodable: _toEncodable);
+}
+
+dynamic _toEncodable(dynamic object) {
+  if (object is OperationResult) {
+    return _operationResultToMap(object);
+  }
+  return object;
+}
+
 Future<Map<String, dynamic>> _deviceToMap(Device device) async {
   return <String, dynamic>{
     'id': device.id,
@@ -963,7 +970,7 @@
     return obj;
   }
   if (obj is OperationResult) {
-    return _operationResultToMap(obj);
+    return obj;
   }
   if (obj is ToolExit) {
     return obj.message;
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index 2bf8050..01d34ce 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -14,7 +14,6 @@
 import '../base/file_system.dart';
 import '../base/utils.dart';
 import '../build_info.dart';
-import '../daemon.dart';
 import '../device.dart';
 import '../features.dart';
 import '../globals.dart' as globals;
@@ -557,10 +556,8 @@
         throwToolExit('"--machine" does not support "-d all".');
       }
       final Daemon daemon = Daemon(
-        DaemonConnection(
-          daemonStreams: StdioDaemonStreams(globals.stdio),
-          logger: globals.logger,
-        ),
+        stdinCommandStream,
+        stdoutCommandResponse,
         notifyingLogger: (globals.logger is NotifyingLogger)
           ? globals.logger as NotifyingLogger
           : NotifyingLogger(verbose: globals.logger.isVerbose, parent: globals.logger),
diff --git a/packages/flutter_tools/lib/src/daemon.dart b/packages/flutter_tools/lib/src/daemon.dart
deleted file mode 100644
index d5be738..0000000
--- a/packages/flutter_tools/lib/src/daemon.dart
+++ /dev/null
@@ -1,241 +0,0 @@
-// 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 'base/common.dart';
-import 'base/io.dart';
-import 'base/logger.dart';
-import 'base/utils.dart';
-import 'convert.dart';
-
-/// Parse binary streams in the JSON RPC format understood by the daemon, and
-/// convert it into a stream of JSON RPC messages.
-Stream<Map<String, Object?>> _convertInputStream(Stream<List<int>> inputStream) {
-  return utf8.decoder.bind(inputStream)
-  .transform<String>(const LineSplitter())
-  .where((String line) => line.startsWith('[{') && line.endsWith('}]'))
-  .map<Map<String, Object?>?>((String line) {
-    line = line.substring(1, line.length - 1);
-    return castStringKeyedMap(json.decode(line));
-  })
-  .where((Map<String, Object?>? entry) => entry != null)
-  .cast<Map<String, Object?>>();
-}
-
-/// A stream that a [DaemonConnection] uses to communicate with each other.
-abstract class DaemonStreams {
-  /// Stream that contains input to the [DaemonConnection].
-  Stream<Map<String, Object?>> get inputStream;
-
-  /// Outputs a message through the connection.
-  void send(Map<String, Object?> message);
-
-  /// Cleans up any resources used.
-  Future<void> dispose() async { }
-}
-
-/// A [DaemonStream] that uses stdin and stdout as the underlying streams.
-class StdioDaemonStreams extends DaemonStreams {
-  StdioDaemonStreams(Stdio stdio) :
-    _stdio = stdio,
-    inputStream = _convertInputStream(stdio.stdin);
-
-  final Stdio _stdio;
-
-  @override
-  final Stream<Map<String, Object?>> inputStream;
-
-  @override
-  void send(Map<String, Object?> message) {
-    _stdio.stdoutWrite(
-      '[${json.encode(message)}]\n',
-      fallback: (String message, Object? error, StackTrace stack) {
-        throwToolExit('Failed to write daemon command response to stdout: $error');
-      },
-    );
-  }
-}
-
-/// A [DaemonStream] that uses [Socket] as the underlying stream.
-class TcpDaemonStreams extends DaemonStreams {
-  /// Creates a [DaemonStreams] with an existing [Socket].
-  TcpDaemonStreams(
-    Socket socket, {
-    required Logger logger,
-  }): _logger = logger {
-    _socket = Future<Socket>.value(_initializeSocket(socket));
-  }
-
-  /// Connects to a remote host and creates a [DaemonStreams] from the socket.
-  TcpDaemonStreams.connect(
-    String host,
-    int port, {
-    required Logger logger,
-  }) : _logger = logger {
-    _socket = Socket.connect(host, port).then(_initializeSocket);
-  }
-
-  late final Future<Socket> _socket;
-  final StreamController<Map<String, Object?>> _commands = StreamController<Map<String, Object?>>();
-  final Logger _logger;
-
-  @override
-  Stream<Map<String, Object?>> get inputStream => _commands.stream;
-
-  @override
-  void send(Map<String, Object?> message) {
-    _socket.then((Socket socket) {
-      try {
-        socket.write('[${json.encode(message)}]\n');
-      } on SocketException catch (error) {
-        _logger.printError('Failed to write daemon command response to socket: $error');
-        // Failed to send, close the connection
-        socket.close();
-      }
-    });
-  }
-
-  Socket _initializeSocket(Socket socket) {
-    _commands.addStream(_convertInputStream(socket));
-    return socket;
-  }
-
-  @override
-  Future<void> dispose() async {
-    await (await _socket).close();
-  }
-}
-
-/// Connection between a flutter daemon and a client.
-class DaemonConnection {
-  DaemonConnection({
-    required DaemonStreams daemonStreams,
-    required Logger logger,
-  }): _logger = logger,
-      _daemonStreams = daemonStreams {
-    _commandSubscription = daemonStreams.inputStream.listen(
-      _handleData,
-      onError: (Object error, StackTrace stackTrace) {
-        // We have to listen for on error otherwise the error on the socket
-        // will end up in the Zone error handler.
-        // Do nothing here and let the stream close handlers handle shutting
-        // down the daemon.
-      }
-    );
-  }
-
-  final DaemonStreams _daemonStreams;
-
-  final Logger _logger;
-
-  late final StreamSubscription<Map<String, Object?>> _commandSubscription;
-
-  int _outgoingRequestId = 0;
-  final Map<String, Completer<Object?>> _outgoingRequestCompleters = <String, Completer<Object?>>{};
-
-  final StreamController<Map<String, Object?>> _events = StreamController<Map<String, Object?>>.broadcast();
-  final StreamController<Map<String, Object?>> _incomingCommands = StreamController<Map<String, Object?>>();
-
-  /// A stream that contains all the incoming requests.
-  Stream<Map<String, Object?>> get incomingCommands => _incomingCommands.stream;
-
-  /// Listens to the event with the event name [eventToListen].
-  Stream<Object?> listenToEvent(String eventToListen) {
-    return _events.stream
-      .where((Map<String, Object?> event) => event['event'] == eventToListen)
-      .map<Object?>((Map<String, Object?> event) => event['params']);
-  }
-
-  /// Sends a request to the other end of the connection.
-  ///
-  /// Returns a [Future] that resolves with the content.
-  Future<Object?> sendRequest(String method, [Object? params]) async {
-    final String id = '${++_outgoingRequestId}';
-    final Completer<Object?> completer = Completer<Object?>();
-    _outgoingRequestCompleters[id] = completer;
-    final Map<String, Object?> data = <String, Object?>{
-      'id': id,
-      'method': method,
-      if (params != null) 'params': params,
-    };
-    _logger.printTrace('-> Sending to daemon, id = $id, method = $method');
-    _daemonStreams.send(data);
-    return completer.future;
-  }
-
-  /// Sends a response to the other end of the connection.
-  void sendResponse(Object id, [Object? result]) {
-    _daemonStreams.send(<String, Object?>{
-      'id': id,
-      if (result != null) 'result': result,
-    });
-  }
-
-  /// Sends an error response to the other end of the connection.
-  void sendErrorResponse(Object id, Object error, StackTrace trace) {
-    _daemonStreams.send(<String, Object?>{
-      'id': id,
-      'error': error,
-      'trace': '$trace',
-    });
-  }
-
-  /// Sends an event to the client.
-  void sendEvent(String name, [ Object? params ]) {
-    _daemonStreams.send(<String, Object?>{
-      'event': name,
-      if (params != null) 'params': params,
-    });
-  }
-
-  /// Handles the input from the stream.
-  ///
-  /// There are three kinds of data: Request, Response, Event.
-  ///
-  /// Request:
-  /// {"id": <Object>. "method": <String>, "params": <optional, Object?>}
-  ///
-  /// Response:
-  /// {"id": <Object>. "result": <optional, Object?>} for a successful response.
-  /// {"id": <Object>. "error": <Object>, "stackTrace": <String>} for an error response.
-  ///
-  /// Event:
-  /// {"event": <String>. "params": <optional, Object?>}
-  void _handleData(Map<String, Object?> data) {
-    if (data['id'] != null) {
-      if (data['method'] == null) {
-        // This is a response to previously sent request.
-        final String id = data['id']! as String;
-        if (data['error'] != null) {
-          // This is an error response.
-          _logger.printTrace('<- Error response received from daemon, id = $id');
-          final Object error = data['error']!;
-          final String stackTrace = data['stackTrace'] as String? ?? '';
-          _outgoingRequestCompleters.remove(id)?.completeError(error, StackTrace.fromString(stackTrace));
-        } else {
-          _logger.printTrace('<- Response received from daemon, id = $id');
-          final Object? result = data['result'];
-          _outgoingRequestCompleters.remove(id)?.complete(result);
-        }
-      } else {
-        _incomingCommands.add(data);
-      }
-    } else if (data['event'] != null) {
-      // This is an event
-      _logger.printTrace('<- Event received: ${data['event']}');
-      _events.add(data);
-    } else {
-      _logger.printError('Unknown data received from daemon');
-    }
-  }
-
-  /// Cleans up any resources used in the connection.
-  Future<void> dispose() async {
-    await _commandSubscription.cancel();
-    await _daemonStreams.dispose();
-    unawaited(_events.close());
-    unawaited(_incomingCommands.close());
-  }
-}
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart
index d9af9f4..fdbd23d 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart
@@ -20,7 +20,6 @@
 import 'package:flutter_tools/src/base/utils.dart';
 import 'package:flutter_tools/src/build_info.dart';
 import 'package:flutter_tools/src/commands/daemon.dart';
-import 'package:flutter_tools/src/daemon.dart';
 import 'package:flutter_tools/src/device.dart';
 import 'package:flutter_tools/src/features.dart';
 import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
@@ -49,92 +48,75 @@
   });
 }
 
-class FakeDaemonStreams extends DaemonStreams {
-  final StreamController<Map<String, dynamic>> inputs = StreamController<Map<String, dynamic>>();
-  final StreamController<Map<String, dynamic>> outputs = StreamController<Map<String, dynamic>>();
-
-  @override
-  Stream<Map<String, dynamic>> get inputStream {
-    return inputs.stream;
-  }
-
-  @override
-  void send(Map<String, dynamic> message) {
-    outputs.add(message);
-  }
-
-  @override
-  Future<void> dispose() async {
-    await inputs.close();
-    // In some tests, outputs have no listeners. We don't wait for outputs to close.
-    unawaited(outputs.close());
-  }
-}
-
 void main() {
   Daemon daemon;
   NotifyingLogger notifyingLogger;
   BufferLogger bufferLogger;
 
   group('daemon', () {
-    FakeDaemonStreams daemonStreams;
-    DaemonConnection daemonConnection;
     setUp(() {
       bufferLogger = BufferLogger.test();
       notifyingLogger = NotifyingLogger(verbose: false, parent: bufferLogger);
-      daemonStreams = FakeDaemonStreams();
-      daemonConnection = DaemonConnection(
-        daemonStreams: daemonStreams,
-        logger: bufferLogger,
-      );
     });
 
-    tearDown(() async {
+    tearDown(() {
       if (daemon != null) {
         return daemon.shutdown();
       }
       notifyingLogger.dispose();
-      await daemonConnection.dispose();
     });
 
     testUsingContext('daemon.version command should succeed', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'daemon.version'});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'daemon.version'});
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
       expect(response['id'], 0);
       expect(response['result'], isNotEmpty);
       expect(response['result'], isA<String>());
+      await responses.close();
+      await commands.close();
     });
 
     testUsingContext('daemon.getSupportedPlatforms command should succeed', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
       // Use the flutter_gallery project which has a known set of supported platforms.
       final String projectPath = globals.fs.path.join(getFlutterRoot(), 'dev', 'integration_tests', 'flutter_gallery');
 
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'daemon.getSupportedPlatforms', 'params': <String, Object>{'projectRoot': projectPath}});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'daemon.getSupportedPlatforms', 'params': <String, Object>{'projectRoot': projectPath}});
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
 
       expect(response['id'], 0);
       expect(response['result'], isNotEmpty);
       expect((response['result'] as Map<String, dynamic>)['platforms'], <String>{'macos'});
+      await responses.close();
+      await commands.close();
     }, overrides: <Type, Generator>{
       // Disable Android/iOS and enable macOS to make sure result is consistent and defaults are tested off.
       FeatureFlags: () => TestFeatureFlags(isAndroidEnabled: false, isIOSEnabled: false, isMacOSEnabled: true),
     });
 
     testUsingContext('printError should send daemon.logMessage event', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
       globals.printError('daemon.logMessage test');
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere((Map<String, dynamic> map) {
+      final Map<String, dynamic> response = await responses.stream.firstWhere((Map<String, dynamic> map) {
         return map['event'] == 'daemon.logMessage' && (map['params'] as Map<String, dynamic>)['level'] == 'error';
       });
       expect(response['id'], isNull);
@@ -142,17 +124,22 @@
       final Map<String, String> logMessage = castStringKeyedMap(response['params']).cast<String, String>();
       expect(logMessage['level'], 'error');
       expect(logMessage['message'], 'daemon.logMessage test');
+      await responses.close();
+      await commands.close();
     }, overrides: <Type, Generator>{
       Logger: () => notifyingLogger,
     });
 
     testUsingContext('printWarning should send daemon.logMessage event', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
       globals.printWarning('daemon.logMessage test');
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere((Map<String, dynamic> map) {
+      final Map<String, dynamic> response = await responses.stream.firstWhere((Map<String, dynamic> map) {
         return map['event'] == 'daemon.logMessage' && (map['params'] as Map<String, dynamic>)['level'] == 'warning';
       });
       expect(response['id'], isNull);
@@ -160,14 +147,19 @@
       final Map<String, String> logMessage = castStringKeyedMap(response['params']).cast<String, String>();
       expect(logMessage['level'], 'warning');
       expect(logMessage['message'], 'daemon.logMessage test');
+      await responses.close();
+      await commands.close();
     }, overrides: <Type, Generator>{
       Logger: () => notifyingLogger,
     });
 
     testUsingContext('printStatus should log to stdout when logToStdout is enabled', () async {
       final StringBuffer buffer = await capturedConsolePrint(() {
+        final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+        final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
         daemon = Daemon(
-          daemonConnection,
+          commands.stream,
+          responses.add,
           notifyingLogger: notifyingLogger,
           logToStdout: true,
         );
@@ -200,89 +192,120 @@
     });
 
     testUsingContext('daemon.shutdown command should stop daemon', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'daemon.shutdown'});
+      commands.add(<String, dynamic>{'id': 0, 'method': 'daemon.shutdown'});
       return daemon.onExit.then<void>((int code) async {
-        await daemonStreams.inputs.close();
+        await commands.close();
         expect(code, 0);
       });
     });
 
     testUsingContext('app.restart without an appId should report an error', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
 
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'app.restart'});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'app.restart'});
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
       expect(response['id'], 0);
       expect(response['error'], contains('appId is required'));
+      await responses.close();
+      await commands.close();
     });
 
     testUsingContext('ext.flutter.debugPaint via service extension without an appId should report an error', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
 
-      daemonStreams.inputs.add(<String, dynamic>{
+      commands.add(<String, dynamic>{
         'id': 0,
         'method': 'app.callServiceExtension',
         'params': <String, String>{
           'methodName': 'ext.flutter.debugPaint',
         },
       });
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
       expect(response['id'], 0);
       expect(response['error'], contains('appId is required'));
+      await responses.close();
+      await commands.close();
     });
 
     testUsingContext('app.stop without appId should report an error', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
 
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'app.stop'});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'app.stop'});
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
       expect(response['id'], 0);
       expect(response['error'], contains('appId is required'));
+      await responses.close();
+      await commands.close();
     });
 
     testUsingContext('device.getDevices should respond with list', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'device.getDevices'});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'device.getDevices'});
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
       expect(response['id'], 0);
       expect(response['result'], isList);
+      await responses.close();
+      await commands.close();
     });
 
     testUsingContext('device.getDevices reports available devices', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
       final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery();
       daemon.deviceDomain.addDeviceDiscoverer(discoverer);
       discoverer.addDevice(FakeAndroidDevice());
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'device.getDevices'});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'device.getDevices'});
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
       expect(response['id'], 0);
       final dynamic result = response['result'];
       expect(result, isList);
       expect(result, isNotEmpty);
+      await responses.close();
+      await commands.close();
     });
 
     testUsingContext('should send device.added event when device is discovered', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
 
@@ -290,12 +313,15 @@
       daemon.deviceDomain.addDeviceDiscoverer(discoverer);
       discoverer.addDevice(FakeAndroidDevice());
 
-      return daemonStreams.outputs.stream.skipWhile(_isConnectedEvent).first.then<void>((Map<String, dynamic> response) async {
+      return responses.stream.skipWhile(_isConnectedEvent).first.then<void>((Map<String, dynamic> response) async {
         expect(response['event'], 'device.added');
         expect(response['params'], isMap);
 
         final Map<String, dynamic> params = castStringKeyedMap(response['params']);
         expect(params['platform'], isNotEmpty); // the fake device has a platform of 'android-arm'
+
+        await responses.close();
+        await commands.close();
       });
     }, overrides: <Type, Generator>{
       AndroidWorkflow: () => FakeAndroidWorkflow(),
@@ -304,90 +330,121 @@
     });
 
     testUsingContext('emulator.launch without an emulatorId should report an error', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
 
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'emulator.launch'});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'emulator.launch'});
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
       expect(response['id'], 0);
       expect(response['error'], contains('emulatorId is required'));
+      await responses.close();
+      await commands.close();
     });
 
     testUsingContext('emulator.launch coldboot parameter must be boolean', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
       final Map<String, dynamic> params = <String, dynamic>{'emulatorId': 'device', 'coldBoot': 1};
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'emulator.launch', 'params': params});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'emulator.launch', 'params': params});
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
       expect(response['id'], 0);
       expect(response['error'], contains('coldBoot is not a bool'));
+      await responses.close();
+      await commands.close();
     });
 
     testUsingContext('emulator.getEmulators should respond with list', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'emulator.getEmulators'});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'emulator.getEmulators'});
+      final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
       expect(response['id'], 0);
       expect(response['result'], isList);
+      await responses.close();
+      await commands.close();
     });
 
     testUsingContext('daemon can send exposeUrl requests to the client', () async {
       const String originalUrl = 'http://localhost:1234/';
       const String mappedUrl = 'https://publichost:4321/';
+      final StreamController<Map<String, dynamic>> input = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> output = StreamController<Map<String, dynamic>>();
 
       daemon = Daemon(
-        daemonConnection,
+        input.stream,
+        output.add,
         notifyingLogger: notifyingLogger,
       );
 
       // Respond to any requests from the daemon to expose a URL.
-      unawaited(daemonStreams.outputs.stream
+      unawaited(output.stream
         .firstWhere((Map<String, dynamic> request) => request['method'] == 'app.exposeUrl')
         .then((Map<String, dynamic> request) {
           expect((request['params'] as Map<String, dynamic>)['url'], equals(originalUrl));
-          daemonStreams.inputs.add(<String, dynamic>{'id': request['id'], 'result': <String, dynamic>{'url': mappedUrl}});
+          input.add(<String, dynamic>{'id': request['id'], 'result': <String, dynamic>{'url': mappedUrl}});
         })
       );
 
       final String exposedUrl = await daemon.daemonDomain.exposeUrl(originalUrl);
       expect(exposedUrl, equals(mappedUrl));
+
+      await output.close();
+      await input.close();
     });
 
     testUsingContext('devtools.serve command should return host and port on success', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
 
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'devtools.serve'});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere((Map<String, dynamic> response) => response['id'] == 0);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'devtools.serve'});
+      final Map<String, dynamic> response = await responses.stream.firstWhere((Map<String, dynamic> response) => response['id'] == 0);
       final Map<String, dynamic> result = response['result'] as Map<String, dynamic>;
       expect(result, isNotEmpty);
       expect(result['host'], '127.0.0.1');
       expect(result['port'], 1234);
+      await responses.close();
+      await commands.close();
     }, overrides: <Type, Generator>{
       DevtoolsLauncher: () => FakeDevtoolsLauncher(DevToolsServerAddress('127.0.0.1', 1234)),
     });
 
     testUsingContext('devtools.serve command should return null fields if null returned', () async {
+      final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
+      final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
       daemon = Daemon(
-        daemonConnection,
+        commands.stream,
+        responses.add,
         notifyingLogger: notifyingLogger,
       );
 
-      daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'devtools.serve'});
-      final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere((Map<String, dynamic> response) => response['id'] == 0);
+      commands.add(<String, dynamic>{'id': 0, 'method': 'devtools.serve'});
+      final Map<String, dynamic> response = await responses.stream.firstWhere((Map<String, dynamic> response) => response['id'] == 0);
       final Map<String, dynamic> result = response['result'] as Map<String, dynamic>;
       expect(result, isNotEmpty);
       expect(result['host'], null);
       expect(result['port'], null);
+      await responses.close();
+      await commands.close();
     }, overrides: <Type, Generator>{
       DevtoolsLauncher: () => FakeDevtoolsLauncher(null),
     });
@@ -426,6 +483,19 @@
     expect(message.message, 'hello');
   });
 
+  group('daemon serialization', () {
+    test('OperationResult', () {
+      expect(
+        jsonEncodeObject(OperationResult.ok),
+        '{"code":0,"message":""}',
+      );
+      expect(
+        jsonEncodeObject(OperationResult(1, 'foo')),
+        '{"code":1,"message":"foo"}',
+      );
+    });
+  });
+
   group('daemon queue', () {
     DebounceOperationQueue<int, String> queue;
     const Duration debounceDuration = Duration(seconds: 1);
diff --git a/packages/flutter_tools/test/general.shard/daemon_test.dart b/packages/flutter_tools/test/general.shard/daemon_test.dart
deleted file mode 100644
index fb2d995..0000000
--- a/packages/flutter_tools/test/general.shard/daemon_test.dart
+++ /dev/null
@@ -1,240 +0,0 @@
-// 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:typed_data';
-
-import 'package:flutter_tools/src/base/common.dart';
-import 'package:flutter_tools/src/base/io.dart';
-import 'package:flutter_tools/src/base/logger.dart';
-import 'package:flutter_tools/src/convert.dart';
-import 'package:flutter_tools/src/daemon.dart';
-import 'package:test/fake.dart';
-
-import '../src/common.dart';
-
-class FakeDaemonStreams extends DaemonStreams {
-  final StreamController<Map<String, dynamic>> inputs = StreamController<Map<String, dynamic>>();
-  final StreamController<Map<String, dynamic>> outputs = StreamController<Map<String, dynamic>>();
-
-  @override
-  Stream<Map<String, dynamic>> get inputStream {
-    return inputs.stream;
-  }
-
-  @override
-  void send(Map<String, dynamic> message) {
-    outputs.add(message);
-  }
-
-  @override
-  Future<void> dispose() async {
-    await inputs.close();
-    // In some tests, outputs have no listeners. We don't wait for outputs to close.
-    unawaited(outputs.close());
-  }
-}
-
-void main() {
-  late BufferLogger bufferLogger;
-  late FakeDaemonStreams daemonStreams;
-  late DaemonConnection daemonConnection;
-  setUp(() {
-    bufferLogger = BufferLogger.test();
-    daemonStreams = FakeDaemonStreams();
-    daemonConnection = DaemonConnection(
-      daemonStreams: daemonStreams,
-      logger: bufferLogger,
-    );
-  });
-
-  tearDown(() async {
-    await daemonConnection.dispose();
-  });
-
-  group('DaemonConnection receiving end', () {
-    testWithoutContext('redirects input to incoming commands', () async {
-      final Map<String, dynamic> commandToSend = <String, dynamic>{'id': 0, 'method': 'some_method'};
-      daemonStreams.inputs.add(commandToSend);
-
-      final Map<String, dynamic> commandReceived = await daemonConnection.incomingCommands.first;
-      await daemonStreams.dispose();
-
-      expect(commandReceived, commandToSend);
-    });
-
-    testWithoutContext('listenToEvent can receive the right events', () async {
-      final Future<List<dynamic>> events = daemonConnection.listenToEvent('event1').toList();
-
-      daemonStreams.inputs.add(<String, dynamic>{'event': 'event1', 'params': '1'});
-      daemonStreams.inputs.add(<String, dynamic>{'event': 'event2', 'params': '2'});
-      daemonStreams.inputs.add(<String, dynamic>{'event': 'event1', 'params': null});
-      daemonStreams.inputs.add(<String, dynamic>{'event': 'event1', 'params': 3});
-
-      await pumpEventQueue();
-      await daemonConnection.dispose();
-
-      expect(await events, <dynamic>['1', null, 3]);
-    });
-  });
-
-  group('DaemonConnection sending end', () {
-    testWithoutContext('sending requests', () async {
-      unawaited(daemonConnection.sendRequest('some_method', 'param'));
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-      expect(data['id'], isNotNull);
-      expect(data['method'], 'some_method');
-      expect(data['params'], 'param');
-    });
-
-    testWithoutContext('sending requests without param', () async {
-      unawaited(daemonConnection.sendRequest('some_method'));
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-      expect(data['id'], isNotNull);
-      expect(data['method'], 'some_method');
-      expect(data['params'], isNull);
-    });
-
-    testWithoutContext('sending response', () async {
-      daemonConnection.sendResponse('1', 'some_data');
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-      expect(data['id'], '1');
-      expect(data['method'], isNull);
-      expect(data['error'], isNull);
-      expect(data['result'], 'some_data');
-    });
-
-    testWithoutContext('sending response without data', () async {
-      daemonConnection.sendResponse('1');
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-      expect(data['id'], '1');
-      expect(data['method'], isNull);
-      expect(data['error'], isNull);
-      expect(data['result'], isNull);
-    });
-
-    testWithoutContext('sending error response', () async {
-      daemonConnection.sendErrorResponse('1', 'error', StackTrace.fromString('stack trace'));
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-      expect(data['id'], '1');
-      expect(data['method'], isNull);
-      expect(data['error'], 'error');
-      expect(data['trace'], 'stack trace');
-    });
-
-    testWithoutContext('sending events', () async {
-      daemonConnection.sendEvent('some_event', '123');
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-      expect(data['id'], isNull);
-      expect(data['event'], 'some_event');
-      expect(data['params'], '123');
-    });
-
-    testWithoutContext('sending events without params', () async {
-      daemonConnection.sendEvent('some_event');
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-      expect(data['id'], isNull);
-      expect(data['event'], 'some_event');
-      expect(data['params'], isNull);
-    });
-  });
-
-  group('DaemonConnection request and response', () {
-    testWithoutContext('receiving response from requests', () async {
-      final Future<dynamic> requestFuture = daemonConnection.sendRequest('some_method', 'param');
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-
-      expect(data['id'], isNotNull);
-      expect(data['method'], 'some_method');
-      expect(data['params'], 'param');
-
-      final String id = data['id'] as String;
-      daemonStreams.inputs.add(<String, dynamic>{'id': id, 'result': '123'});
-      expect(await requestFuture, '123');
-    });
-
-    testWithoutContext('receiving response from requests without result', () async {
-      final Future<dynamic> requestFuture = daemonConnection.sendRequest('some_method', 'param');
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-
-      expect(data['id'], isNotNull);
-      expect(data['method'], 'some_method');
-      expect(data['params'], 'param');
-
-      final String id = data['id'] as String;
-      daemonStreams.inputs.add(<String, dynamic>{'id': id});
-      expect(await requestFuture, null);
-    });
-
-    testWithoutContext('receiving error response from requests without result', () async {
-      final Future<dynamic> requestFuture = daemonConnection.sendRequest('some_method', 'param');
-      final Map<String, dynamic> data = await daemonStreams.outputs.stream.first;
-
-      expect(data['id'], isNotNull);
-      expect(data['method'], 'some_method');
-      expect(data['params'], 'param');
-
-      final String id = data['id'] as String;
-      daemonStreams.inputs.add(<String, dynamic>{'id': id, 'error': 'some_error', 'trace': 'stack trace'});
-      expect(requestFuture, throwsA('some_error'));
-    });
-  });
-
-  group('TcpDaemonStreams', () {
-    final Map<String, Object?> testCommand = <String, Object?>{
-      'id': 100,
-      'method': 'test',
-    };
-    late FakeSocket socket;
-    late TcpDaemonStreams daemonStreams;
-    setUp(() {
-      socket = FakeSocket();
-      daemonStreams = TcpDaemonStreams(socket, logger: bufferLogger);
-    });
-
-    test('parses the message received on the socket', () async {
-      socket.controller.add(Uint8List.fromList(utf8.encode('[${jsonEncode(testCommand)}]\n')));
-      final Map<String, Object?> command = await daemonStreams.inputStream.first;
-      expect(command, testCommand);
-    });
-
-    test('sends the encoded message through the socket', () async {
-      daemonStreams.send(testCommand);
-      await pumpEventQueue();
-      expect(socket.writtenObjects.length, 1);
-      expect(socket.writtenObjects[0].toString(), '[${jsonEncode(testCommand)}]\n');
-    });
-
-    test('dispose calls socket.close', () async {
-      await daemonStreams.dispose();
-      expect(socket.closeCalled, isTrue);
-    });
-  });
-}
-
-class FakeSocket extends Fake implements Socket {
-  bool closeCalled = false;
-  final StreamController<Uint8List> controller = StreamController<Uint8List>();
-  final List<Object?> writtenObjects = <Object?>[];
-
-  @override
-  StreamSubscription<Uint8List> listen(
-    void Function(Uint8List event)? onData, {
-    Function? onError,
-    void Function()? onDone,
-    bool? cancelOnError,
-  }) {
-    return controller.stream.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
-  }
-
-  @override
-  void write(Object? object) {
-    writtenObjects.add(object);
-  }
-
-  @override
-  Future<void> close() async {
-    closeCalled = true;
-  }
-}