Unverified Commit 96320ae7 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] remove mocks from devFS test (#82471)

parent 344f3ab7
......@@ -14,13 +14,15 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:mockito/mockito.dart';
import 'package:package_config/package_config.dart';
import 'package:test/fake.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/fake_http_client.dart';
import '../src/fake_vm_services.dart';
import '../src/fakes.dart';
......@@ -123,7 +125,7 @@ void main() {
testWithoutContext('DevFS create throws a DevFSException when vmservice disconnects unexpectedly', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
final OperatingSystemUtils osUtils = FakeOperatingSystemUtils();
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[failingCreateDevFSRequest],
httpAddress: Uri.parse('http://localhost'),
......@@ -143,7 +145,7 @@ void main() {
testWithoutContext('DevFS destroy is resilient to vmservice disconnection', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
final OperatingSystemUtils osUtils = FakeOperatingSystemUtils();
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
createDevFSRequest,
......@@ -168,26 +170,28 @@ void main() {
testWithoutContext('DevFS retries uploads when connection reset by peer', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
final MockResidentCompiler residentCompiler = MockResidentCompiler();
final OperatingSystemUtils osUtils = OperatingSystemUtils(
fileSystem: fileSystem,
platform: FakePlatform(),
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
);
final FakeResidentCompiler residentCompiler = FakeResidentCompiler();
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[createDevFSRequest],
httpAddress: Uri.parse('http://localhost'),
);
when(residentCompiler.recompile(
any,
any,
outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async {
residentCompiler.onRecompile = (Uri mainUri, List<Uri> invalidatedFiles) async {
fileSystem.file('lib/foo.dill')
..createSync(recursive: true)
..writeAsBytesSync(<int>[1, 2, 3, 4, 5]);
return const CompilerOutput('lib/foo.dill', 0, <Uri>[]);
});
};
/// This output can change based on the host platform.
final List<List<int>> expectedEncoded = await osUtils.gzipLevel1Stream(
Stream<List<int>>.value(<int>[1, 2, 3, 4, 5]),
).toList();
final DevFS devFS = DevFS(
fakeVmServiceHost.vmService,
......@@ -202,7 +206,8 @@ void main() {
FakeRequest(Uri.parse('http://localhost'), method: HttpMethod.put, responseError: const OSError('Connection Reset by peer')),
FakeRequest(Uri.parse('http://localhost'), method: HttpMethod.put, responseError: const OSError('Connection Reset by peer')),
FakeRequest(Uri.parse('http://localhost'), method: HttpMethod.put, responseError: const OSError('Connection Reset by peer')),
FakeRequest(Uri.parse('http://localhost'), method: HttpMethod.put)
// This is the value of `<int>[1, 2, 3, 4, 5]` run through `osUtils.gzipLevel1Stream`.
FakeRequest(Uri.parse('http://localhost'), method: HttpMethod.put, body: <int>[for (List<int> chunk in expectedEncoded) ...chunk])
]),
uploadRetryThrottle: Duration.zero,
);
......@@ -220,7 +225,6 @@ void main() {
expect(report.syncedBytes, 5);
expect(report.success, isTrue);
verify(osUtils.gzipLevel1Stream(any)).called(6);
});
testWithoutContext('DevFS reports unsuccessful compile when errors are returned', () async {
......@@ -243,17 +247,10 @@ void main() {
await devFS.create();
final DateTime previousCompile = devFS.lastCompiled;
final MockResidentCompiler residentCompiler = MockResidentCompiler();
when(residentCompiler.recompile(
any,
any,
outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async {
final FakeResidentCompiler residentCompiler = FakeResidentCompiler();
residentCompiler.onRecompile = (Uri mainUri, List<Uri> invalidatedFiles) async {
return const CompilerOutput('lib/foo.dill', 2, <Uri>[]);
});
};
final UpdateFSReport report = await devFS.update(
mainUri: Uri.parse('lib/foo.txt'),
......@@ -289,18 +286,11 @@ void main() {
await devFS.create();
final DateTime previousCompile = devFS.lastCompiled;
final MockResidentCompiler residentCompiler = MockResidentCompiler();
when(residentCompiler.recompile(
any,
any,
outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async {
fileSystem.file('example').createSync();
final FakeResidentCompiler residentCompiler = FakeResidentCompiler();
residentCompiler.onRecompile = (Uri mainUri, List<Uri> invalidatedFiles) async {
fileSystem.file('lib/foo.txt.dill').createSync(recursive: true);
return const CompilerOutput('lib/foo.txt.dill', 0, <Uri>[]);
});
};
final UpdateFSReport report = await devFS.update(
mainUri: Uri.parse('lib/main.dart'),
......@@ -337,18 +327,11 @@ void main() {
await devFS.create();
final DateTime previousCompile = devFS.lastCompiled;
final MockResidentCompiler residentCompiler = MockResidentCompiler();
when(residentCompiler.recompile(
any,
any,
outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async {
final FakeResidentCompiler residentCompiler = FakeResidentCompiler();
residentCompiler.onRecompile = (Uri mainUri, List<Uri> invalidatedFiles) async {
fileSystem.file('lib/foo.txt.dill').createSync(recursive: true);
return const CompilerOutput('lib/foo.txt.dill', 0, <Uri>[]);
});
};
final UpdateFSReport report = await devFS.update(
mainUri: Uri.parse('lib/main.dart'),
......@@ -391,18 +374,11 @@ void main() {
await devFS.create();
final MockResidentCompiler residentCompiler = MockResidentCompiler();
when(residentCompiler.recompile(
any,
any,
outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async {
final FakeResidentCompiler residentCompiler = FakeResidentCompiler();
residentCompiler.onRecompile = (Uri mainUri, List<Uri> invalidatedFiles) async {
fileSystem.file('example').createSync();
return const CompilerOutput('lib/foo.txt.dill', 0, <Uri>[]);
});
};
expect(writer.written, false);
......@@ -439,10 +415,11 @@ void main() {
});
testWithoutContext('Local DevFSWriter turns FileSystemException into DevFSException', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FileExceptionHandler handler = FileExceptionHandler();
final FileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle);
final LocalDevFSWriter writer = LocalDevFSWriter(fileSystem: fileSystem);
final File file = MockFile();
when(file.copySync(any)).thenThrow(const FileSystemException('foo'));
final File file = fileSystem.file('foo');
handler.addError(file, FileSystemOp.read, const FileSystemException('foo'));
await expectLater(() async => writer.write(<Uri, DevFSContent>{
Uri.parse('goodbye'): DevFSFileContent(file),
......@@ -450,9 +427,16 @@ void main() {
});
}
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
class MockResidentCompiler extends Mock implements ResidentCompiler {}
class MockFile extends Mock implements File {}
class FakeResidentCompiler extends Fake implements ResidentCompiler {
Future<CompilerOutput> Function(Uri mainUri, List<Uri> invalidatedFiles) onRecompile;
@override
Future<CompilerOutput> recompile(Uri mainUri, List<Uri> invalidatedFiles, {String outputPath, PackageConfig packageConfig, String projectRootPath, FileSystem fs, bool suppressErrors = false}) {
return onRecompile?.call(mainUri, invalidatedFiles)
?? Future<CompilerOutput>.value(const CompilerOutput('', 1, <Uri>[]));
}
}
class FakeDevFSWriter implements DevFSWriter {
bool written = false;
......
......@@ -7,6 +7,8 @@ import 'dart:convert';
import 'dart:io';
import 'package:collection/collection.dart';
/// The HTTP verb for a [FakeRequest].
enum HttpMethod {
get,
......@@ -85,12 +87,14 @@ class FakeRequest {
this.method = HttpMethod.get,
this.response = FakeResponse.empty,
this.responseError,
this.body,
});
final Uri uri;
final HttpMethod method;
final FakeResponse response;
final Object? responseError;
final List<int>? body;
@override
String toString() => 'Request{${_toMethodString(method)}, $uri}';
......@@ -182,7 +186,7 @@ class FakeHttpClient implements HttpClient {
@override
Future<HttpClientRequest> deleteUrl(Uri url) async {
return _findRequest(HttpMethod.delete, url);
return _findRequest(HttpMethod.delete, url, StackTrace.current);
}
@override
......@@ -196,7 +200,7 @@ class FakeHttpClient implements HttpClient {
@override
Future<HttpClientRequest> getUrl(Uri url) async {
return _findRequest(HttpMethod.get, url);
return _findRequest(HttpMethod.get, url, StackTrace.current);
}
@override
......@@ -207,7 +211,7 @@ class FakeHttpClient implements HttpClient {
@override
Future<HttpClientRequest> headUrl(Uri url) async {
return _findRequest(HttpMethod.head, url);
return _findRequest(HttpMethod.head, url, StackTrace.current);
}
@override
......@@ -218,7 +222,7 @@ class FakeHttpClient implements HttpClient {
@override
Future<HttpClientRequest> openUrl(String method, Uri url) async {
return _findRequest(_fromMethodString(method), url);
return _findRequest(_fromMethodString(method), url, StackTrace.current);
}
@override
......@@ -229,7 +233,7 @@ class FakeHttpClient implements HttpClient {
@override
Future<HttpClientRequest> patchUrl(Uri url) async {
return _findRequest(HttpMethod.patch, url);
return _findRequest(HttpMethod.patch, url, StackTrace.current);
}
@override
......@@ -240,7 +244,7 @@ class FakeHttpClient implements HttpClient {
@override
Future<HttpClientRequest> postUrl(Uri url) async {
return _findRequest(HttpMethod.post, url);
return _findRequest(HttpMethod.post, url, StackTrace.current);
}
@override
......@@ -251,12 +255,12 @@ class FakeHttpClient implements HttpClient {
@override
Future<HttpClientRequest> putUrl(Uri url) async {
return _findRequest(HttpMethod.put, url);
return _findRequest(HttpMethod.put, url, StackTrace.current);
}
int _requestCount = 0;
_FakeHttpClientRequest _findRequest(HttpMethod method, Uri uri) {
_FakeHttpClientRequest _findRequest(HttpMethod method, Uri uri, StackTrace stackTrace) {
// Ensure the fake client throws similar errors to the real client.
if (uri.host.isEmpty) {
throw ArgumentError('No host specified in URI $uri');
......@@ -270,6 +274,8 @@ class FakeHttpClient implements HttpClient {
uri,
methodString,
null,
null,
stackTrace,
);
}
FakeRequest? matchedRequest;
......@@ -292,17 +298,22 @@ class FakeHttpClient implements HttpClient {
uri,
methodString,
matchedRequest.responseError,
matchedRequest.body,
stackTrace,
);
}
}
class _FakeHttpClientRequest implements HttpClientRequest {
_FakeHttpClientRequest(this._response, this._uri, this._method, this._responseError);
_FakeHttpClientRequest(this._response, this._uri, this._method, this._responseError, this._expectedBody, this._stackTrace);
final FakeResponse _response;
final String _method;
final Uri _uri;
final Object? _responseError;
final List<int> _body = <int>[];
final List<int>? _expectedBody;
final StackTrace _stackTrace;
@override
bool bufferOutput = true;
......@@ -328,16 +339,33 @@ class _FakeHttpClientRequest implements HttpClientRequest {
}
@override
void add(List<int> data) { }
void add(List<int> data) {
_body.addAll(data);
}
@override
void addError(Object error, [StackTrace? stackTrace]) { }
@override
Future<void> addStream(Stream<List<int>> stream) async { }
Future<void> addStream(Stream<List<int>> stream) async {
final Completer<void> completer = Completer<void>();
stream.listen(_body.addAll, onDone: completer.complete);
await completer.future;
}
@override
Future<HttpClientResponse> close() async {
final Completer<void> completer = Completer<void>();
Timer.run(() {
if (_expectedBody != null && !const ListEquality<int>().equals(_expectedBody, _body)) {
completer.completeError(StateError(
'Expected a request with the following body:\n$_expectedBody\n but found:\n$_body'
), _stackTrace);
} else {
completer.complete();
}
});
await completer.future;
if (_responseError != null) {
return Future<HttpClientResponse>.error(_responseError!);
}
......@@ -366,16 +394,24 @@ class _FakeHttpClientRequest implements HttpClientRequest {
Uri get uri => _uri;
@override
void write(Object? object) { }
void write(Object? object) {
_body.addAll(utf8.encode(object.toString()));
}
@override
void writeAll(Iterable<dynamic> objects, [String separator = '']) { }
void writeAll(Iterable<dynamic> objects, [String separator = '']) {
_body.addAll(utf8.encode(objects.join(separator)));
}
@override
void writeCharCode(int charCode) { }
void writeCharCode(int charCode) {
_body.add(charCode);
}
@override
void writeln([Object? object = '']) { }
void writeln([Object? object = '']) {
_body.addAll(utf8.encode(object.toString() + '\n'));
}
}
class _FakeHttpClientResponse extends Stream<List<int>> implements HttpClientResponse {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment