Revert "Devfs cleanup and testing (#33374)" (#33673)

This reverts commit 445505d6f2d4a0b658385f0ef735d3a826ca49ab.
diff --git a/packages/flutter_tools/test/devfs_test.dart b/packages/flutter_tools/test/devfs_test.dart
index 1887e74..b8d93d4 100644
--- a/packages/flutter_tools/test/devfs_test.dart
+++ b/packages/flutter_tools/test/devfs_test.dart
@@ -4,17 +4,15 @@
 
 import 'dart:async';
 import 'dart:convert';
+import 'dart:io'; // ignore: dart_io_import
 
 import 'package:file/file.dart';
 import 'package:file/memory.dart';
-import 'package:flutter_tools/src/base/context.dart';
 import 'package:flutter_tools/src/base/file_system.dart';
 import 'package:flutter_tools/src/base/io.dart';
-import 'package:flutter_tools/src/base/platform.dart';
 import 'package:flutter_tools/src/devfs.dart';
 import 'package:flutter_tools/src/vmservice.dart';
 import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
-import 'package:mockito/mockito.dart';
 
 import 'src/common.dart';
 import 'src/context.dart';
@@ -22,39 +20,17 @@
 
 void main() {
   FileSystem fs;
-  MockPlatform mockPlatform;
+  String filePath;
+  Directory tempDir;
+  String basePath;
+  DevFS devFS;
 
-  setUp(() {
-    fs = MemoryFileSystem(style: FileSystemStyle.posix);
-    mockPlatform = MockPlatform();
-    when(mockPlatform.pathSeparator).thenReturn('/');
-    when(mockPlatform.isWindows).thenReturn(false);
+  setUpAll(() {
+    fs = MemoryFileSystem();
+    filePath = fs.path.join('lib', 'foo.txt');
   });
 
   group('DevFSContent', () {
-    test('copyToFile', () {
-      final String filePath = fs.path.join('lib', 'foo.txt');
-      final File file = fs.file(filePath)
-        ..createSync(recursive: true)
-        ..writeAsStringSync('hello, world');
-      final DevFSByteContent byteContent = DevFSByteContent(<int>[4, 5, 6]);
-      final DevFSStringContent stringContent = DevFSStringContent('some string');
-      final DevFSFileContent fileContent = DevFSFileContent(file);
-
-      final File byteDestination = fs.file('byte_dest');
-      final File stringDestination = fs.file('string_dest');
-      final File fileDestination = fs.file('file_dest');
-
-      byteContent.copyToFile(byteDestination);
-      expect(byteDestination.readAsBytesSync(), <int>[4, 5, 6]);
-
-      stringContent.copyToFile(stringDestination);
-      expect(stringDestination.readAsStringSync(), 'some string');
-
-      fileContent.copyToFile(fileDestination);
-      expect(fileDestination.readAsStringSync(), 'hello, world');
-    });
-
     test('bytes', () {
       final DevFSByteContent content = DevFSByteContent(<int>[4, 5, 6]);
       expect(content.bytes, orderedEquals(<int>[4, 5, 6]));
@@ -65,7 +41,6 @@
       expect(content.isModified, isTrue);
       expect(content.isModified, isFalse);
     });
-
     test('string', () {
       final DevFSStringContent content = DevFSStringContent('some string');
       expect(content.string, 'some string');
@@ -83,9 +58,7 @@
       expect(content.isModified, isTrue);
       expect(content.isModified, isFalse);
     });
-
     testUsingContext('file', () async {
-      final String filePath = fs.path.join('lib', 'foo.txt');
       final File file = fs.file(filePath);
       final DevFSFileContent content = DevFSFileContent(file);
       expect(content.isModified, isFalse);
@@ -100,9 +73,10 @@
       expect(content.isModifiedAfter(null), isTrue);
 
       file.writeAsBytesSync(<int>[2, 3, 4], flush: true);
+      expect(content.fileDependencies, <String>[filePath]);
       expect(content.isModified, isTrue);
       expect(content.isModified, isFalse);
-      expect(content.contentsAsBytes(), <int>[2, 3, 4]);
+      expect(await content.contentsAsBytes(), <int>[2, 3, 4]);
       updateFileModificationTime(file.path, fiveSecondsAgo, 0);
       expect(content.isModified, isFalse);
       expect(content.isModified, isFalse);
@@ -113,56 +87,36 @@
       expect(content.isModified, isFalse);
     }, overrides: <Type, Generator>{
       FileSystem: () => fs,
-    }, skip: platform.isWindows); // Still flaky, but only on CI :(
+    }, skip: Platform.isWindows); // TODO(jonahwilliams): fix or disable this functionality.
   });
 
   group('devfs remote', () {
-    DevFS devFS;
-    MockResidentCompiler residentCompiler;
-    MockDevFSOperations mockDevFSOperations;
-    int created;
-    int destroyed;
-    List<String> writtenFiles;
-    bool exists;
+    MockVMService vmService;
+    final MockResidentCompiler residentCompiler = MockResidentCompiler();
 
-    setUp(() async {
-      mockDevFSOperations = MockDevFSOperations();
-      devFS = DevFS.operations(mockDevFSOperations, 'test', fs.currentDirectory);
-      residentCompiler = MockResidentCompiler();
-      created = 0;
-      destroyed = 0;
-      exists = false;
-      writtenFiles = <String>[];
-      when(mockDevFSOperations.create('test')).thenAnswer((Invocation invocation) async {
-        if (exists) {
-          throw rpc.RpcException(1001, 'already exists');
-        }
-        exists = true;
-        created += 1;
-        return Uri.parse(InternetAddress.loopbackIPv4.toString());
-      });
-      when(mockDevFSOperations.destroy('test')).thenAnswer((Invocation invocation) async {
-        exists = false;
-        destroyed += 1;
-      });
-      when(mockDevFSOperations.write(any)).thenAnswer((Invocation invocation) async {
-        final Map<Uri, DevFSContent> entries = invocation.positionalArguments.first;
-        writtenFiles.addAll(entries.keys.map((Uri uri) => uri.toFilePath()));
-      });
+    setUpAll(() async {
+      tempDir = _newTempDir(fs);
+      basePath = tempDir.path;
+      vmService = MockVMService();
+      await vmService.setUp();
+    });
+    tearDownAll(() async {
+      await vmService.tearDown();
+      _cleanupTempDirs();
     });
 
     testUsingContext('create dev file system', () async {
       // simulate workspace
-      final String filePath = fs.path.join('lib', 'foo.txt');
-      final File file = fs.file(filePath);
+      final File file = fs.file(fs.path.join(basePath, filePath));
       await file.parent.create(recursive: true);
       file.writeAsBytesSync(<int>[1, 2, 3]);
 
       // simulate package
       await _createPackage(fs, 'somepkg', 'somefile.txt');
-      await devFS.create();
 
-      expect(created, 1);
+      devFS = DevFS(vmService, 'test', tempDir);
+      await devFS.create();
+      vmService.expectMessages(<String>['create test']);
       expect(devFS.assetPathsToEvict, isEmpty);
 
       final UpdateFSReport report = await devFS.update(
@@ -172,8 +126,9 @@
         trackWidgetCreation: false,
         invalidatedFiles: <Uri>[],
       );
-
-      expect(writtenFiles.single, contains('foo.txt.dill'));
+      vmService.expectMessages(<String>[
+        'writeFile test lib/foo.txt.dill',
+      ]);
       expect(devFS.assetPathsToEvict, isEmpty);
       expect(report.syncedBytes, 22);
       expect(report.success, true);
@@ -182,8 +137,9 @@
     });
 
     testUsingContext('delete dev file system', () async {
+      expect(vmService.messages, isEmpty, reason: 'prior test timeout');
       await devFS.destroy();
-      expect(destroyed, 1);
+      vmService.expectMessages(<String>['destroy test']);
       expect(devFS.assetPathsToEvict, isEmpty);
     }, overrides: <Type, Generator>{
       FileSystem: () => fs,
@@ -191,27 +147,26 @@
 
     testUsingContext('cleanup preexisting file system', () async {
       // simulate workspace
-      final String filePath = fs.path.join('lib', 'foo.txt');
-      final File file = fs.file(filePath);
+      final File file = fs.file(fs.path.join(basePath, filePath));
       await file.parent.create(recursive: true);
       file.writeAsBytesSync(<int>[1, 2, 3]);
 
       // simulate package
       await _createPackage(fs, 'somepkg', 'somefile.txt');
 
+      devFS = DevFS(vmService, 'test', tempDir);
       await devFS.create();
-      expect(created, 1);
+      vmService.expectMessages(<String>['create test']);
       expect(devFS.assetPathsToEvict, isEmpty);
 
       // Try to create again.
       await devFS.create();
-      expect(created, 2);
-      expect(destroyed, 1);
+      vmService.expectMessages(<String>['create test', 'destroy test', 'create test']);
       expect(devFS.assetPathsToEvict, isEmpty);
 
       // Really destroy.
       await devFS.destroy();
-      expect(destroyed, 2);
+      vmService.expectMessages(<String>['destroy test']);
       expect(devFS.assetPathsToEvict, isEmpty);
     }, overrides: <Type, Generator>{
       FileSystem: () => fs,
@@ -219,20 +174,113 @@
   });
 }
 
-class MockVMService extends Mock implements VMService {}
+class MockVMService extends BasicMock implements VMService {
+  MockVMService() {
+    _vm = MockVM(this);
+  }
 
-class MockDevFSOperations extends Mock implements DevFSOperations {}
+  Uri _httpAddress;
+  HttpServer _server;
+  MockVM _vm;
 
-class MockPlatform extends Mock implements Platform {}
+  @override
+  Uri get httpAddress => _httpAddress;
 
+  @override
+  VM get vm => _vm;
+
+  Future<void> setUp() async {
+    try {
+      _server = await HttpServer.bind(InternetAddress.loopbackIPv6, 0);
+      _httpAddress = Uri.parse('http://[::1]:${_server.port}');
+    } on SocketException {
+      // Fall back to IPv4 if the host doesn't support binding to IPv6 localhost
+      _server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
+      _httpAddress = Uri.parse('http://127.0.0.1:${_server.port}');
+    }
+    _server.listen((HttpRequest request) {
+      final String fsName = request.headers.value('dev_fs_name');
+      final String devicePath = utf8.decode(base64.decode(request.headers.value('dev_fs_uri_b64')));
+      messages.add('writeFile $fsName $devicePath');
+      request.drain<List<int>>().then<void>((List<int> value) {
+        request.response
+          ..write('Got it')
+          ..close();
+      });
+    });
+  }
+
+  Future<void> tearDown() async {
+    await _server?.close();
+  }
+
+  @override
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockVM implements VM {
+  MockVM(this._service);
+
+  final MockVMService _service;
+  final Uri _baseUri = Uri.parse('file:///tmp/devfs/test');
+  bool _devFSExists = false;
+
+  static const int kFileSystemAlreadyExists = 1001;
+
+  @override
+  Future<Map<String, dynamic>> createDevFS(String fsName) async {
+    _service.messages.add('create $fsName');
+    if (_devFSExists) {
+      throw rpc.RpcException(kFileSystemAlreadyExists, 'File system already exists');
+    }
+    _devFSExists = true;
+    return <String, dynamic>{'uri': '$_baseUri'};
+  }
+
+  @override
+  Future<Map<String, dynamic>> deleteDevFS(String fsName) async {
+    _service.messages.add('destroy $fsName');
+    _devFSExists = false;
+    return <String, dynamic>{'type': 'Success'};
+  }
+
+  @override
+  Future<Map<String, dynamic>> invokeRpcRaw(
+    String method, {
+    Map<String, dynamic> params = const <String, dynamic>{},
+    Duration timeout,
+    bool timeoutFatal = true,
+  }) async {
+    _service.messages.add('$method $params');
+    return <String, dynamic>{'success': true};
+  }
+
+  @override
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+final List<Directory> _tempDirs = <Directory>[];
 final Map <String, Uri> _packages = <String, Uri>{};
 
+Directory _newTempDir(FileSystem fs) {
+  final Directory tempDir = fs.systemTempDirectory.createTempSync('flutter_devfs${_tempDirs.length}_test.');
+  _tempDirs.add(tempDir);
+  return tempDir;
+}
+
+void _cleanupTempDirs() {
+  while (_tempDirs.isNotEmpty)
+    tryToDelete(_tempDirs.removeLast());
+}
 
 Future<void> _createPackage(FileSystem fs, String pkgName, String pkgFileName, { bool doubleSlash = false }) async {
-  String pkgFilePath = fs.path.join(pkgName, 'lib', pkgFileName);
+  final Directory pkgTempDir = _newTempDir(fs);
+  String pkgFilePath = fs.path.join(pkgTempDir.path, pkgName, 'lib', pkgFileName);
   if (doubleSlash) {
     // Force two separators into the path.
-    pkgFilePath = fs.path.join(pkgName, 'lib', pkgFileName);
+    final String doubleSlash = fs.path.separator + fs.path.separator;
+    pkgFilePath = pkgTempDir.path + doubleSlash + fs.path.join(pkgName, 'lib', pkgFileName);
   }
   final File pkgFile = fs.file(pkgFilePath);
   await pkgFile.parent.create(recursive: true);
@@ -242,5 +290,6 @@
   _packages.forEach((String pkgName, Uri pkgUri) {
     sb.writeln('$pkgName:$pkgUri');
   });
-  fs.file('.packages').writeAsStringSync(sb.toString());
+  fs.file(fs.path.join(_tempDirs[0].path, '.packages')).writeAsStringSync(sb.toString());
 }
+