mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[flutter_tools] use a single fake implementation of HttpClient (#75471)
This commit is contained in:
parent
645cb64392
commit
8df58eb650
@ -48,6 +48,7 @@ class Net {
|
||||
Future<List<int>> fetchUrl(Uri url, {
|
||||
int maxAttempts,
|
||||
File destFile,
|
||||
@visibleForTesting Duration durationOverride,
|
||||
}) async {
|
||||
int attempts = 0;
|
||||
int durationSeconds = 1;
|
||||
@ -78,7 +79,7 @@ class Net {
|
||||
'Download failed -- attempting retry $attempts in '
|
||||
'$durationSeconds second${ durationSeconds == 1 ? "" : "s"}...',
|
||||
);
|
||||
await Future<void>.delayed(Duration(seconds: durationSeconds));
|
||||
await Future<void>.delayed(durationOverride ?? Duration(seconds: durationSeconds));
|
||||
if (durationSeconds < 64) {
|
||||
durationSeconds *= 2;
|
||||
}
|
||||
@ -173,8 +174,6 @@ class Net {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// An IOSink that collects whatever is written to it.
|
||||
class _MemoryIOSink implements IOSink {
|
||||
@override
|
||||
|
@ -78,7 +78,6 @@ void main() {
|
||||
MockPortForwarder portForwarder;
|
||||
MockDartDevelopmentService mockDds;
|
||||
MockAndroidDevice device;
|
||||
MockHttpClient httpClient;
|
||||
|
||||
setUp(() {
|
||||
fakeLogReader = FakeDeviceLogReader();
|
||||
@ -98,13 +97,6 @@ void main() {
|
||||
when(mockDds.startDartDevelopmentService(any, any, false, any)).thenReturn(null);
|
||||
when(mockDds.uri).thenReturn(Uri.parse('http://localhost:8181'));
|
||||
when(mockDds.done).thenAnswer((_) => noopCompleter.future);
|
||||
final HttpClientRequest httpClientRequest = MockHttpClientRequest();
|
||||
httpClient = MockHttpClient();
|
||||
when(httpClient.putUrl(any))
|
||||
.thenAnswer((_) => Future<HttpClientRequest>.value(httpClientRequest));
|
||||
when(httpClientRequest.headers).thenReturn(MockHttpHeaders());
|
||||
when(httpClientRequest.close())
|
||||
.thenAnswer((_) => Future<HttpClientResponse>.value(MockHttpClientResponse()));
|
||||
|
||||
// We cannot add the device to a device manager because that is
|
||||
// only enabled by the context of each testUsingContext call.
|
||||
@ -925,6 +917,3 @@ class TestHotRunnerFactory extends HotRunnerFactory {
|
||||
}
|
||||
|
||||
class MockDartDevelopmentService extends Mock implements DartDevelopmentService {}
|
||||
class MockHttpClientRequest extends Mock implements HttpClientRequest {}
|
||||
class MockHttpClientResponse extends Mock implements HttpClientResponse {}
|
||||
class MockHttpHeaders extends Mock implements HttpHeaders {}
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:file_testing/file_testing.dart';
|
||||
@ -31,6 +30,7 @@ import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fake_http_client.dart';
|
||||
import '../../src/pubspec_schema.dart';
|
||||
import '../../src/testbed.dart';
|
||||
|
||||
@ -1627,7 +1627,16 @@ void main() {
|
||||
expect(projectDir.childDirectory('lib').childFile('main.dart').readAsStringSync(),
|
||||
contains('void main() {}'));
|
||||
}, overrides: <Type, Generator>{
|
||||
HttpClientFactory: () => () => MockHttpClient(200, result: 'void main() {}'),
|
||||
HttpClientFactory: () {
|
||||
return () {
|
||||
return FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(
|
||||
Uri.parse('https://master-api.flutter.dev/snippets/foo.bar.Baz.dart'),
|
||||
response: FakeResponse(body: utf8.encode('void main() {}')),
|
||||
)
|
||||
]);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
testUsingContext('null-safe sample-based project have no analyzer errors', () async {
|
||||
@ -1641,7 +1650,16 @@ void main() {
|
||||
contains('String?'), // uses null-safe syntax
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
HttpClientFactory: () => () => MockHttpClient(200, result: 'void main() { String? foo; print(foo); }'),
|
||||
HttpClientFactory: () {
|
||||
return () {
|
||||
return FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(
|
||||
Uri.parse('https://master-api.flutter.dev/snippets/foo.bar.Baz.dart'),
|
||||
response: FakeResponse(body: utf8.encode('void main() { String? foo; print(foo); }')),
|
||||
)
|
||||
]);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
testUsingContext('can write samples index to disk', () async {
|
||||
@ -1659,8 +1677,16 @@ void main() {
|
||||
expect(expectedFile, exists);
|
||||
expect(expectedFile.readAsStringSync(), equals(samplesIndexJson));
|
||||
}, overrides: <Type, Generator>{
|
||||
HttpClientFactory: () =>
|
||||
() => MockHttpClient(200, result: samplesIndexJson),
|
||||
HttpClientFactory: () {
|
||||
return () {
|
||||
return FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(
|
||||
Uri.parse('https://master-api.flutter.dev/snippets/index.json'),
|
||||
response: FakeResponse(body: utf8.encode(samplesIndexJson)),
|
||||
)
|
||||
]);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
testUsingContext('Throws tool exit on empty samples index', () async {
|
||||
@ -1680,8 +1706,15 @@ void main() {
|
||||
message: 'Unable to download samples',
|
||||
));
|
||||
}, overrides: <Type, Generator>{
|
||||
HttpClientFactory: () =>
|
||||
() => MockHttpClient(200, result: ''),
|
||||
HttpClientFactory: () {
|
||||
return () {
|
||||
return FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(
|
||||
Uri.parse('https://master-api.flutter.dev/snippets/index.json'),
|
||||
)
|
||||
]);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
testUsingContext('provides an error to the user if samples json download fails', () async {
|
||||
@ -1697,8 +1730,16 @@ void main() {
|
||||
await expectLater(runner.run(args), throwsToolExit(exitCode: 2, message: 'Failed to write samples'));
|
||||
expect(globals.fs.file(outputFile), isNot(exists));
|
||||
}, overrides: <Type, Generator>{
|
||||
HttpClientFactory: () =>
|
||||
() => MockHttpClient(404, result: 'not found'),
|
||||
HttpClientFactory: () {
|
||||
return () {
|
||||
return FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(
|
||||
Uri.parse('https://master-api.flutter.dev/snippets/index.json'),
|
||||
response: const FakeResponse(statusCode: HttpStatus.notFound),
|
||||
)
|
||||
]);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
testUsingContext('plugin does not support any platform by default', () async {
|
||||
@ -2655,76 +2696,3 @@ class LoggingProcessManager extends LocalProcessManager {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MockHttpClient implements HttpClient {
|
||||
MockHttpClient(this.statusCode, {this.result});
|
||||
|
||||
final int statusCode;
|
||||
final String result;
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> getUrl(Uri url) async {
|
||||
return MockHttpClientRequest(statusCode, result: result);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw 'io.HttpClient - $invocation';
|
||||
}
|
||||
}
|
||||
|
||||
class MockHttpClientRequest implements HttpClientRequest {
|
||||
MockHttpClientRequest(this.statusCode, {this.result});
|
||||
|
||||
final int statusCode;
|
||||
final String result;
|
||||
|
||||
@override
|
||||
Future<HttpClientResponse> close() async {
|
||||
return MockHttpClientResponse(statusCode, result: result);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw 'io.HttpClientRequest - $invocation';
|
||||
}
|
||||
}
|
||||
|
||||
class MockHttpClientResponse implements HttpClientResponse {
|
||||
MockHttpClientResponse(this.statusCode, {this.result});
|
||||
|
||||
@override
|
||||
final int statusCode;
|
||||
|
||||
final String result;
|
||||
|
||||
@override
|
||||
String get reasonPhrase => '<reason phrase>';
|
||||
|
||||
@override
|
||||
HttpClientResponseCompressionState get compressionState {
|
||||
return HttpClientResponseCompressionState.decompressed;
|
||||
}
|
||||
|
||||
@override
|
||||
StreamSubscription<Uint8List> listen(
|
||||
void onData(Uint8List event), {
|
||||
Function onError,
|
||||
void onDone(),
|
||||
bool cancelOnError,
|
||||
}) {
|
||||
return Stream<Uint8List>.fromIterable(<Uint8List>[Uint8List.fromList(result.codeUnits)])
|
||||
.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<dynamic> forEach(void Function(Uint8List element) action) {
|
||||
action(Uint8List.fromList(result.codeUnits));
|
||||
return Future<void>.value();
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw 'io.HttpClientResponse - $invocation';
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/fake_http_client.dart';
|
||||
import '../src/fakes.dart';
|
||||
|
||||
final Platform testPlatform = FakePlatform(environment: const <String, String>{});
|
||||
@ -32,7 +33,7 @@ void main() {
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -55,7 +56,7 @@ void main() {
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -80,17 +81,19 @@ void main() {
|
||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||
final BufferLogger logger = BufferLogger.test();
|
||||
final MockHttpClient client = MockHttpClient();
|
||||
client.testRequest.testResponse.headers = FakeHttpHeaders(<String, List<String>>{
|
||||
'x-goog-hash': <String>[],
|
||||
});
|
||||
|
||||
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||
fileSystem: fileSystem,
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: client,
|
||||
httpClient: FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(
|
||||
headers: <String, List<String>>{
|
||||
'x-goog-hash': <String>[],
|
||||
}
|
||||
)),
|
||||
]),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -109,20 +112,23 @@ void main() {
|
||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||
final BufferLogger logger = BufferLogger.test();
|
||||
final MockHttpClient client = MockHttpClient();
|
||||
client.testRequest.testResponse.headers = FakeHttpHeaders(<String, List<String>>{
|
||||
'x-goog-hash': <String>[
|
||||
'foo-bar-baz',
|
||||
'md5=k7iFrf4NoInN9jSQT9WfcQ=='
|
||||
],
|
||||
});
|
||||
|
||||
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||
fileSystem: fileSystem,
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: client,
|
||||
httpClient: FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(
|
||||
body: <int>[0],
|
||||
headers: <String, List<String>>{
|
||||
'x-goog-hash': <String>[
|
||||
'foo-bar-baz',
|
||||
'md5=k7iFrf4NoInN9jSQT9WfcQ=='
|
||||
],
|
||||
}
|
||||
)),
|
||||
]),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -141,20 +147,31 @@ void main() {
|
||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||
final BufferLogger logger = BufferLogger.test();
|
||||
final MockHttpClient client = MockHttpClient();
|
||||
client.testRequest.testResponse.headers = FakeHttpHeaders(<String, List<String>>{
|
||||
'x-goog-hash': <String>[
|
||||
'foo-bar-baz',
|
||||
'md5=k7iFrf4SQT9WfcQ=='
|
||||
],
|
||||
});
|
||||
|
||||
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||
fileSystem: fileSystem,
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: client,
|
||||
httpClient: FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(
|
||||
body: <int>[0],
|
||||
headers: <String, List<String>>{
|
||||
'x-goog-hash': <String>[
|
||||
'foo-bar-baz',
|
||||
'md5=k7iFrf4SQT9WfcQ=='
|
||||
],
|
||||
}
|
||||
)),
|
||||
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(
|
||||
headers: <String, List<String>>{
|
||||
'x-goog-hash': <String>[
|
||||
'foo-bar-baz',
|
||||
'md5=k7iFrf4SQT9WfcQ=='
|
||||
],
|
||||
}
|
||||
)),
|
||||
]),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -179,7 +196,10 @@ void main() {
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: MockHttpClient()..exceptionOnFirstRun = true,
|
||||
httpClient: FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http:///test.zip'), responseError: const HttpException('')),
|
||||
FakeRequest(Uri.parse('http:///test.zip')),
|
||||
]),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -197,14 +217,16 @@ void main() {
|
||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||
final BufferLogger logger = BufferLogger.test();
|
||||
final MockHttpClient client = MockHttpClient();
|
||||
client.testRequest.testResponse.statusCode = HttpStatus.preconditionFailed;
|
||||
|
||||
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||
fileSystem: fileSystem,
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: client,
|
||||
httpClient: FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(statusCode: HttpStatus.preconditionFailed)),
|
||||
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(statusCode: HttpStatus.preconditionFailed)),
|
||||
]),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -215,7 +237,6 @@ void main() {
|
||||
fileSystem.currentDirectory.childDirectory('out'),
|
||||
), throwsToolExit());
|
||||
|
||||
expect(client.attempts, 2);
|
||||
expect(logger.statusText, contains('test message'));
|
||||
expect(fileSystem.file('out/test'), isNot(exists));
|
||||
});
|
||||
@ -224,8 +245,6 @@ void main() {
|
||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||
final BufferLogger logger = BufferLogger.test();
|
||||
final MockHttpClient client = MockHttpClient();
|
||||
client.argumentError = true;
|
||||
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||
fileSystem: fileSystem,
|
||||
logger: logger,
|
||||
@ -235,7 +254,9 @@ void main() {
|
||||
'FLUTTER_STORAGE_BASE_URL': 'foo-bar'
|
||||
},
|
||||
),
|
||||
httpClient: client,
|
||||
httpClient: FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http:///foo-bar/test.zip'), responseError: ArgumentError())
|
||||
]),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -246,7 +267,6 @@ void main() {
|
||||
fileSystem.currentDirectory.childDirectory('out'),
|
||||
), throwsToolExit());
|
||||
|
||||
expect(client.attempts, 1);
|
||||
expect(logger.statusText, contains('test message'));
|
||||
expect(fileSystem.file('out/test'), isNot(exists));
|
||||
});
|
||||
@ -255,14 +275,14 @@ void main() {
|
||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||
final BufferLogger logger = BufferLogger.test();
|
||||
final MockHttpClient client = MockHttpClient();
|
||||
client.argumentError = true;
|
||||
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||
fileSystem: fileSystem,
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: client,
|
||||
httpClient: FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http:///test.zip'), responseError: ArgumentError()),
|
||||
]),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -273,7 +293,6 @@ void main() {
|
||||
fileSystem.currentDirectory.childDirectory('out'),
|
||||
), throwsA(isA<ArgumentError>()));
|
||||
|
||||
expect(client.attempts, 1);
|
||||
expect(logger.statusText, contains('test message'));
|
||||
expect(fileSystem.file('out/test'), isNot(exists));
|
||||
});
|
||||
@ -287,7 +306,7 @@ void main() {
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -311,7 +330,7 @@ void main() {
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -335,7 +354,7 @@ void main() {
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -359,7 +378,7 @@ void main() {
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -383,7 +402,7 @@ void main() {
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -405,7 +424,7 @@ void main() {
|
||||
logger: logger,
|
||||
operatingSystemUtils: operatingSystemUtils,
|
||||
platform: testPlatform,
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||
..createSync(),
|
||||
);
|
||||
@ -448,57 +467,3 @@ class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {
|
||||
.createSync();
|
||||
}
|
||||
}
|
||||
|
||||
class MockHttpClient extends Mock implements HttpClient {
|
||||
int attempts = 0;
|
||||
bool argumentError = false;
|
||||
bool exceptionOnFirstRun = false;
|
||||
final MockHttpClientRequest testRequest = MockHttpClientRequest();
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> getUrl(Uri url) async {
|
||||
if (exceptionOnFirstRun && attempts == 0) {
|
||||
attempts += 1;
|
||||
throw Exception();
|
||||
}
|
||||
attempts += 1;
|
||||
if (argumentError) {
|
||||
throw ArgumentError();
|
||||
}
|
||||
return testRequest;
|
||||
}
|
||||
}
|
||||
|
||||
class MockHttpClientRequest extends Mock implements HttpClientRequest {
|
||||
final MockHttpClientResponse testResponse = MockHttpClientResponse();
|
||||
|
||||
@override
|
||||
Future<HttpClientResponse> close() async {
|
||||
return testResponse;
|
||||
}
|
||||
}
|
||||
|
||||
class MockHttpClientResponse extends Mock implements HttpClientResponse {
|
||||
@override
|
||||
int statusCode = HttpStatus.ok;
|
||||
|
||||
@override
|
||||
HttpHeaders headers = FakeHttpHeaders(<String, List<String>>{});
|
||||
|
||||
@override
|
||||
Future<void> forEach(void Function(List<int> element) action) async {
|
||||
action(<int>[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeHttpHeaders extends Fake implements HttpHeaders {
|
||||
FakeHttpHeaders(this.values);
|
||||
|
||||
final Map<String, List<String>> values;
|
||||
|
||||
@override
|
||||
List<String> operator [](String key) {
|
||||
return values[key];
|
||||
}
|
||||
}
|
||||
|
@ -4,45 +4,32 @@
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/base/bot_detector.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/persistent_tool_state.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:fake_async/fake_async.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/fake_http_client.dart';
|
||||
import '../../src/fakes.dart';
|
||||
|
||||
final Uri azureUrl = Uri.parse('http://169.254.169.254/metadata/instance');
|
||||
|
||||
void main() {
|
||||
group('BotDetector', () {
|
||||
FakePlatform fakePlatform;
|
||||
FakeStdio fakeStdio;
|
||||
MockHttpClient mockHttpClient;
|
||||
MockHttpClientRequest mockHttpClientRequest;
|
||||
MockHttpHeaders mockHttpHeaders;
|
||||
BotDetector botDetector;
|
||||
PersistentToolState persistentToolState;
|
||||
|
||||
setUp(() {
|
||||
fakePlatform = FakePlatform()..environment = <String, String>{};
|
||||
fakeStdio = FakeStdio();
|
||||
mockHttpClient = MockHttpClient();
|
||||
mockHttpClientRequest = MockHttpClientRequest();
|
||||
mockHttpHeaders = MockHttpHeaders();
|
||||
persistentToolState = PersistentToolState.test(
|
||||
directory: MemoryFileSystem.test().currentDirectory,
|
||||
logger: BufferLogger.test(),
|
||||
);
|
||||
botDetector = BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => mockHttpClient,
|
||||
persistentToolState: persistentToolState,
|
||||
);
|
||||
});
|
||||
|
||||
group('isRunningOnBot', () {
|
||||
@ -50,6 +37,12 @@ void main() {
|
||||
fakePlatform.environment['BOT'] = 'false';
|
||||
fakePlatform.environment['TRAVIS'] = 'true';
|
||||
|
||||
final BotDetector botDetector = BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => FakeHttpClient.any(),
|
||||
persistentToolState: persistentToolState,
|
||||
);
|
||||
|
||||
expect(await botDetector.isRunningOnBot, isFalse);
|
||||
expect(persistentToolState.isRunningOnBot, isFalse);
|
||||
});
|
||||
@ -58,14 +51,25 @@ void main() {
|
||||
fakePlatform.environment['FLUTTER_HOST'] = 'foo';
|
||||
fakePlatform.environment['TRAVIS'] = 'true';
|
||||
|
||||
final BotDetector botDetector = BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => FakeHttpClient.any(),
|
||||
persistentToolState: persistentToolState,
|
||||
);
|
||||
|
||||
expect(await botDetector.isRunningOnBot, isFalse);
|
||||
expect(persistentToolState.isRunningOnBot, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('returns false with and without a terminal attached', () async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
throw const SocketException('HTTP connection timed out');
|
||||
});
|
||||
final BotDetector botDetector = BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(azureUrl, responseError: const SocketException('HTTP connection timed out')),
|
||||
]),
|
||||
persistentToolState: persistentToolState,
|
||||
);
|
||||
|
||||
fakeStdio.stdout.hasTerminal = true;
|
||||
expect(await botDetector.isRunningOnBot, isFalse);
|
||||
fakeStdio.stdout.hasTerminal = false;
|
||||
@ -76,38 +80,52 @@ void main() {
|
||||
testWithoutContext('can test analytics outputs on bots when outputting to a file', () async {
|
||||
fakePlatform.environment['TRAVIS'] = 'true';
|
||||
fakePlatform.environment['FLUTTER_ANALYTICS_LOG_FILE'] = '/some/file';
|
||||
|
||||
final BotDetector botDetector = BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => FakeHttpClient.any(),
|
||||
persistentToolState: persistentToolState,
|
||||
);
|
||||
|
||||
expect(await botDetector.isRunningOnBot, isFalse);
|
||||
expect(persistentToolState.isRunningOnBot, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('returns true when azure metadata is reachable', () async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
return Future<HttpClientRequest>.value(mockHttpClientRequest);
|
||||
});
|
||||
when(mockHttpClientRequest.headers).thenReturn(mockHttpHeaders);
|
||||
final BotDetector botDetector = BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => FakeHttpClient.any(),
|
||||
persistentToolState: persistentToolState,
|
||||
);
|
||||
|
||||
expect(await botDetector.isRunningOnBot, isTrue);
|
||||
expect(persistentToolState.isRunningOnBot, isTrue);
|
||||
});
|
||||
|
||||
testWithoutContext('caches azure bot detection results across instances', () async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
return Future<HttpClientRequest>.value(mockHttpClientRequest);
|
||||
});
|
||||
when(mockHttpClientRequest.headers).thenReturn(mockHttpHeaders);
|
||||
final BotDetector botDetector = BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => FakeHttpClient.any(),
|
||||
persistentToolState: persistentToolState,
|
||||
);
|
||||
|
||||
expect(await botDetector.isRunningOnBot, isTrue);
|
||||
expect(await BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => mockHttpClient,
|
||||
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[]),
|
||||
persistentToolState: persistentToolState,
|
||||
).isRunningOnBot, isTrue);
|
||||
verify(mockHttpClient.getUrl(any)).called(1);
|
||||
});
|
||||
|
||||
testWithoutContext('returns true when running on borg', () async {
|
||||
fakePlatform.environment['BORG_ALLOC_DIR'] = 'true';
|
||||
|
||||
final BotDetector botDetector = BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => FakeHttpClient.any(),
|
||||
persistentToolState: persistentToolState,
|
||||
);
|
||||
|
||||
expect(await botDetector.isRunningOnBot, isTrue);
|
||||
expect(persistentToolState.isRunningOnBot, isTrue);
|
||||
});
|
||||
@ -115,60 +133,34 @@ void main() {
|
||||
});
|
||||
|
||||
group('AzureDetector', () {
|
||||
AzureDetector azureDetector;
|
||||
MockHttpClient mockHttpClient;
|
||||
MockHttpClientRequest mockHttpClientRequest;
|
||||
MockHttpHeaders mockHttpHeaders;
|
||||
|
||||
setUp(() {
|
||||
mockHttpClient = MockHttpClient();
|
||||
mockHttpClientRequest = MockHttpClientRequest();
|
||||
mockHttpHeaders = MockHttpHeaders();
|
||||
azureDetector = AzureDetector(
|
||||
httpClientFactory: () => mockHttpClient,
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('isRunningOnAzure returns false when connection times out', () async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
throw const SocketException('HTTP connection timed out');
|
||||
});
|
||||
final AzureDetector azureDetector = AzureDetector(
|
||||
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(azureUrl, responseError: const SocketException('HTTP connection timed out')),
|
||||
],
|
||||
));
|
||||
|
||||
expect(await azureDetector.isRunningOnAzure, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('isRunningOnAzure returns false when the http request times out', () {
|
||||
FakeAsync().run((FakeAsync time) async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
final Completer<HttpClientRequest> completer = Completer<HttpClientRequest>();
|
||||
return completer.future; // Never completed to test timeout behavior.
|
||||
});
|
||||
final Future<bool> onBot = azureDetector.isRunningOnAzure;
|
||||
time.elapse(const Duration(seconds: 2));
|
||||
|
||||
expect(await onBot, isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
testWithoutContext('isRunningOnAzure returns false when OsError is thrown', () async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
throw const OSError('Connection Refused', 111);
|
||||
});
|
||||
final AzureDetector azureDetector = AzureDetector(
|
||||
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(azureUrl, responseError: const OSError('Connection Refused', 111)),
|
||||
],
|
||||
));
|
||||
|
||||
expect(await azureDetector.isRunningOnAzure, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('isRunningOnAzure returns true when azure metadata is reachable', () async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
return Future<HttpClientRequest>.value(mockHttpClientRequest);
|
||||
});
|
||||
when(mockHttpClientRequest.headers).thenReturn(mockHttpHeaders);
|
||||
final AzureDetector azureDetector = AzureDetector(
|
||||
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(azureUrl),
|
||||
],
|
||||
));
|
||||
|
||||
expect(await azureDetector.isRunningOnAzure, isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class MockHttpClient extends Mock implements HttpClient {}
|
||||
class MockHttpClientRequest extends Mock implements HttpClientRequest {}
|
||||
class MockHttpHeaders extends Mock implements HttpHeaders {}
|
||||
|
@ -4,19 +4,20 @@
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart' as io;
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/net.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:fake_async/fake_async.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/fake_http_client.dart';
|
||||
|
||||
void main() {
|
||||
BufferLogger testLogger;
|
||||
@ -42,75 +43,93 @@ void main() {
|
||||
});
|
||||
|
||||
testWithoutContext('fetchUrl() gets the data', () async {
|
||||
final Net net = createNet(FakeHttpClient(200, data: responseString));
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http://example.invalid/'), response: FakeResponse(
|
||||
body: utf8.encode(responseString),
|
||||
)),
|
||||
])
|
||||
);
|
||||
|
||||
final List<int> data = await net.fetchUrl(Uri.parse('http://example.invalid/'));
|
||||
expect(data, equals(responseData));
|
||||
});
|
||||
|
||||
testWithoutContext('fetchUrl(destFile) writes the data to a file', () async {
|
||||
final Net net = createNet(FakeHttpClient(200, data: responseString));
|
||||
final MemoryFileSystem fs = MemoryFileSystem.test();
|
||||
final File destFile = fs.file('dest_file')..createSync();
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http://example.invalid/'), response: FakeResponse(
|
||||
body: utf8.encode(responseString),
|
||||
)),
|
||||
])
|
||||
);
|
||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||
final File destFile = fileSystem.file('dest_file')..createSync();
|
||||
final List<int> data = await net.fetchUrl(
|
||||
Uri.parse('http://example.invalid/'),
|
||||
destFile: destFile,
|
||||
);
|
||||
expect(data, equals(<int>[]));
|
||||
expect(destFile.readAsStringSync(), equals(responseString));
|
||||
expect(destFile.readAsStringSync(), responseString);
|
||||
});
|
||||
});
|
||||
|
||||
testWithoutContext('retry from 500', () async {
|
||||
final Net net = createNet(FakeHttpClient(500));
|
||||
String error;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
net.fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
||||
error = 'test completed unexpectedly';
|
||||
}, onError: (dynamic exception) {
|
||||
error = 'test failed unexpectedly: $exception';
|
||||
});
|
||||
expect(testLogger.statusText, '');
|
||||
time.elapse(const Duration(milliseconds: 10000));
|
||||
expect(testLogger.statusText,
|
||||
'Download failed -- attempting retry 1 in 1 second...\n'
|
||||
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
||||
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
||||
'Download failed -- attempting retry 4 in 8 seconds...\n',
|
||||
);
|
||||
});
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('http://example.invalid/'), response: const FakeResponse(statusCode: io.HttpStatus.internalServerError)),
|
||||
FakeRequest(Uri.parse('http://example.invalid/'), response: const FakeResponse(statusCode: io.HttpStatus.internalServerError)),
|
||||
FakeRequest(Uri.parse('http://example.invalid/'), response: const FakeResponse(statusCode: io.HttpStatus.internalServerError)),
|
||||
FakeRequest(Uri.parse('http://example.invalid/'), response: const FakeResponse(statusCode: io.HttpStatus.internalServerError)),
|
||||
])
|
||||
);
|
||||
|
||||
await net.fetchUrl(Uri.parse('http://example.invalid/'), maxAttempts: 4, durationOverride: Duration.zero);
|
||||
|
||||
expect(testLogger.statusText,
|
||||
'Download failed -- attempting retry 1 in 1 second...\n'
|
||||
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
||||
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
||||
'Download failed -- retry 4\n',
|
||||
);
|
||||
expect(testLogger.errorText, isEmpty);
|
||||
expect(error, isNull);
|
||||
});
|
||||
|
||||
testWithoutContext('retry from network error', () async {
|
||||
final Net net = createNet(FakeHttpClient(200));
|
||||
String error;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
net.fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
||||
error = 'test completed unexpectedly';
|
||||
}, onError: (dynamic exception) {
|
||||
error = 'test failed unexpectedly: $exception';
|
||||
});
|
||||
expect(testLogger.statusText, '');
|
||||
time.elapse(const Duration(milliseconds: 10000));
|
||||
expect(testLogger.statusText,
|
||||
'Download failed -- attempting retry 1 in 1 second...\n'
|
||||
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
||||
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
||||
'Download failed -- attempting retry 4 in 8 seconds...\n',
|
||||
);
|
||||
});
|
||||
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
||||
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
||||
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
||||
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
||||
])
|
||||
);
|
||||
|
||||
await net.fetchUrl(Uri.parse('http://example.invalid/'), maxAttempts: 4, durationOverride: Duration.zero);
|
||||
|
||||
expect(testLogger.statusText,
|
||||
'Download failed -- attempting retry 1 in 1 second...\n'
|
||||
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
||||
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
||||
'Download failed -- retry 4\n',
|
||||
);
|
||||
expect(testLogger.errorText, isEmpty);
|
||||
expect(error, isNull);
|
||||
});
|
||||
|
||||
testWithoutContext('retry from SocketException', () async {
|
||||
final Net net = createNet(FakeHttpClientThrowing(
|
||||
const io.SocketException('test exception handling'),
|
||||
));
|
||||
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(invalid, responseError: const io.SocketException('')),
|
||||
FakeRequest(invalid, responseError: const io.SocketException('')),
|
||||
FakeRequest(invalid, responseError: const io.SocketException('')),
|
||||
FakeRequest(invalid, responseError: const io.SocketException('')),
|
||||
])
|
||||
);
|
||||
String error;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
net.fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
||||
net.fetchUrl(invalid).then((List<int> value) {
|
||||
error = 'test completed unexpectedly';
|
||||
}, onError: (dynamic exception) {
|
||||
error = 'test failed unexpectedly: $exception';
|
||||
@ -130,12 +149,18 @@ void main() {
|
||||
});
|
||||
|
||||
testWithoutContext('no retry from HandshakeException', () async {
|
||||
final Net net = createNet(FakeHttpClientThrowing(
|
||||
const io.HandshakeException('test exception handling'),
|
||||
));
|
||||
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(invalid, responseError: const io.HandshakeException('')),
|
||||
FakeRequest(invalid, responseError: const io.HandshakeException('')),
|
||||
FakeRequest(invalid, responseError: const io.HandshakeException('')),
|
||||
FakeRequest(invalid, responseError: const io.HandshakeException('')),
|
||||
])
|
||||
);
|
||||
String error;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
net.fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
||||
net.fetchUrl(invalid).then((List<int> value) {
|
||||
error = 'test completed unexpectedly';
|
||||
}, onError: (dynamic exception) {
|
||||
error = 'test failed: $exception';
|
||||
@ -149,10 +174,13 @@ void main() {
|
||||
});
|
||||
|
||||
testWithoutContext('check for bad override on ArgumentError', () async {
|
||||
final Uri invalid = Uri.parse('example.invalid/');
|
||||
final Net net = Net(
|
||||
httpClientFactory: () => FakeHttpClientThrowing(
|
||||
ArgumentError('test exception handling'),
|
||||
),
|
||||
httpClientFactory: () {
|
||||
return FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(invalid, responseError: ArgumentError()),
|
||||
]);
|
||||
},
|
||||
logger: testLogger,
|
||||
platform: FakePlatform(
|
||||
environment: <String, String>{
|
||||
@ -177,12 +205,18 @@ void main() {
|
||||
});
|
||||
|
||||
testWithoutContext('retry from HttpException', () async {
|
||||
final Net net = createNet(FakeHttpClientThrowing(
|
||||
const io.HttpException('test exception handling'),
|
||||
));
|
||||
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(invalid, responseError: const io.HttpException('')),
|
||||
FakeRequest(invalid, responseError: const io.HttpException('')),
|
||||
FakeRequest(invalid, responseError: const io.HttpException('')),
|
||||
FakeRequest(invalid, responseError: const io.HttpException('')),
|
||||
])
|
||||
);
|
||||
String error;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
net.fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
||||
net.fetchUrl(invalid).then((List<int> value) {
|
||||
error = 'test completed unexpectedly';
|
||||
}, onError: (dynamic exception) {
|
||||
error = 'test failed unexpectedly: $exception';
|
||||
@ -202,12 +236,18 @@ void main() {
|
||||
});
|
||||
|
||||
testWithoutContext('retry from HttpException when request throws', () async {
|
||||
final Net net = createNet(FakeHttpClientThrowingRequest(
|
||||
const io.HttpException('test exception handling'),
|
||||
));
|
||||
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(invalid, responseError: const io.HttpException('')),
|
||||
FakeRequest(invalid, responseError: const io.HttpException('')),
|
||||
FakeRequest(invalid, responseError: const io.HttpException('')),
|
||||
FakeRequest(invalid, responseError: const io.HttpException('')),
|
||||
])
|
||||
);
|
||||
String error;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
net.fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
||||
net.fetchUrl(invalid).then((List<int> value) {
|
||||
error = 'test completed unexpectedly';
|
||||
}, onError: (dynamic exception) {
|
||||
error = 'test failed unexpectedly: $exception';
|
||||
@ -227,11 +267,24 @@ void main() {
|
||||
});
|
||||
|
||||
testWithoutContext('max attempts', () async {
|
||||
final Net net = createNet(FakeHttpClient(500));
|
||||
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(invalid, response: const FakeResponse(
|
||||
statusCode: HttpStatus.internalServerError,
|
||||
)),
|
||||
FakeRequest(invalid, response: const FakeResponse(
|
||||
statusCode: HttpStatus.internalServerError,
|
||||
)),
|
||||
FakeRequest(invalid, response: const FakeResponse(
|
||||
statusCode: HttpStatus.internalServerError,
|
||||
)),
|
||||
])
|
||||
);
|
||||
String error;
|
||||
List<int> actualResult;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
net.fetchUrl(Uri.parse('http://example.invalid/'), maxAttempts: 3).then((List<int> value) {
|
||||
net.fetchUrl(invalid, maxAttempts: 3).then((List<int> value) {
|
||||
actualResult = value;
|
||||
}, onError: (dynamic exception) {
|
||||
error = 'test failed unexpectedly: $exception';
|
||||
@ -249,155 +302,40 @@ void main() {
|
||||
expect(actualResult, isNull);
|
||||
});
|
||||
|
||||
testWithoutContext('remote file non-existant', () async {
|
||||
final Net net = createNet(FakeHttpClient(404));
|
||||
testWithoutContext('remote file non-existent', () async {
|
||||
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(invalid, method: HttpMethod.head, response: const FakeResponse(
|
||||
statusCode: HttpStatus.notFound,
|
||||
)),
|
||||
])
|
||||
);
|
||||
final bool result = await net.doesRemoteFileExist(invalid);
|
||||
expect(result, false);
|
||||
});
|
||||
|
||||
testWithoutContext('remote file server error', () async {
|
||||
final Net net = createNet(FakeHttpClient(500));
|
||||
final Uri valid = Uri.parse('http://example.valid/');
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(valid, method: HttpMethod.head, response: const FakeResponse(
|
||||
statusCode: HttpStatus.internalServerError,
|
||||
)),
|
||||
])
|
||||
);
|
||||
final bool result = await net.doesRemoteFileExist(valid);
|
||||
expect(result, false);
|
||||
});
|
||||
|
||||
testWithoutContext('remote file exists', () async {
|
||||
final Net net = createNet(FakeHttpClient(200));
|
||||
final Uri valid = Uri.parse('http://example.valid/');
|
||||
final Net net = createNet(
|
||||
FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(valid, method: HttpMethod.head),
|
||||
])
|
||||
);
|
||||
final bool result = await net.doesRemoteFileExist(valid);
|
||||
expect(result, true);
|
||||
});
|
||||
}
|
||||
|
||||
class FakeHttpClientThrowing implements io.HttpClient {
|
||||
FakeHttpClientThrowing(this.exception);
|
||||
|
||||
final Object exception;
|
||||
|
||||
@override
|
||||
Future<io.HttpClientRequest> getUrl(Uri url) async {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw 'io.HttpClient - $invocation';
|
||||
}
|
||||
}
|
||||
|
||||
class FakeHttpClient implements io.HttpClient {
|
||||
FakeHttpClient(this.statusCode, { this.data });
|
||||
|
||||
final int statusCode;
|
||||
final String data;
|
||||
|
||||
@override
|
||||
Future<io.HttpClientRequest> getUrl(Uri url) async {
|
||||
return FakeHttpClientRequest(statusCode, data: data);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<io.HttpClientRequest> headUrl(Uri url) async {
|
||||
return FakeHttpClientRequest(statusCode);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw 'io.HttpClient - $invocation';
|
||||
}
|
||||
}
|
||||
|
||||
class FakeHttpClientThrowingRequest implements io.HttpClient {
|
||||
FakeHttpClientThrowingRequest(this.exception);
|
||||
|
||||
final Object exception;
|
||||
|
||||
@override
|
||||
Future<io.HttpClientRequest> getUrl(Uri url) async {
|
||||
return FakeHttpClientRequestThrowing(exception);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw 'io.HttpClient - $invocation';
|
||||
}
|
||||
}
|
||||
|
||||
class FakeHttpClientRequest implements io.HttpClientRequest {
|
||||
FakeHttpClientRequest(this.statusCode, { this.data });
|
||||
|
||||
final int statusCode;
|
||||
final String data;
|
||||
|
||||
@override
|
||||
Future<io.HttpClientResponse> close() async {
|
||||
return FakeHttpClientResponse(statusCode, data: data);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw 'io.HttpClientRequest - $invocation';
|
||||
}
|
||||
}
|
||||
|
||||
class FakeHttpClientRequestThrowing implements io.HttpClientRequest {
|
||||
FakeHttpClientRequestThrowing(this.exception);
|
||||
|
||||
final Object exception;
|
||||
|
||||
@override
|
||||
Future<io.HttpClientResponse> close() async {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw 'io.HttpClientRequest - $invocation';
|
||||
}
|
||||
}
|
||||
|
||||
class FakeHttpClientResponse implements io.HttpClientResponse {
|
||||
FakeHttpClientResponse(this.statusCode, { this.data });
|
||||
|
||||
@override
|
||||
final int statusCode;
|
||||
|
||||
final String data;
|
||||
|
||||
@override
|
||||
String get reasonPhrase => '<reason phrase>';
|
||||
|
||||
@override
|
||||
StreamSubscription<List<int>> listen(
|
||||
void onData(List<int> event), {
|
||||
Function onError,
|
||||
void onDone(),
|
||||
bool cancelOnError,
|
||||
}) {
|
||||
if (data == null) {
|
||||
return Stream<List<int>>.fromFuture(Future<List<int>>.error(
|
||||
const io.SocketException('test'),
|
||||
)).listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
} else {
|
||||
return Stream<List<int>>.fromFuture(Future<List<int>>.value(
|
||||
utf8.encode(data),
|
||||
)).listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<dynamic> forEach(void Function(List<int> element) action) async {
|
||||
if (data == null) {
|
||||
return Future<void>.error(const io.SocketException('test'));
|
||||
} else {
|
||||
return Future<void>.microtask(() => action(utf8.encode(data)));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
throw 'io.HttpClientResponse - $invocation';
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import 'package:http/testing.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/context.dart';
|
||||
import '../src/testbed.dart';
|
||||
import '../src/fake_http_client.dart';
|
||||
|
||||
void main() {
|
||||
BufferLogger logger;
|
||||
@ -79,7 +79,7 @@ void main() {
|
||||
fileSystem: fs,
|
||||
logger: logger,
|
||||
flutterProjectFactory: FlutterProjectFactory(fileSystem: fs, logger: logger),
|
||||
client: FakeHttpClient(),
|
||||
client: FakeHttpClient.any(),
|
||||
);
|
||||
|
||||
final File file = fs.file('flutter_00.log');
|
||||
|
@ -22,6 +22,7 @@ import 'package:package_config/package_config.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/context.dart';
|
||||
import '../src/fake_http_client.dart';
|
||||
|
||||
final FakeVmServiceRequest createDevFSRequest = FakeVmServiceRequest(
|
||||
method: '_createDevFS',
|
||||
@ -110,7 +111,6 @@ void main() {
|
||||
});
|
||||
|
||||
testWithoutContext('DevFS create throws a DevFSException when vmservice disconnects unexpectedly', () async {
|
||||
final HttpClient httpClient = MockHttpClient();
|
||||
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
|
||||
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||
@ -118,16 +118,6 @@ void main() {
|
||||
);
|
||||
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
|
||||
|
||||
final MockHttpClientRequest httpRequest = MockHttpClientRequest();
|
||||
when(httpRequest.headers).thenReturn(MockHttpHeaders());
|
||||
when(httpClient.putUrl(any)).thenAnswer((Invocation invocation) {
|
||||
return Future<HttpClientRequest>.value(httpRequest);
|
||||
});
|
||||
final MockHttpClientResponse httpClientResponse = MockHttpClientResponse();
|
||||
when(httpRequest.close()).thenAnswer((Invocation invocation) {
|
||||
return Future<HttpClientResponse>.value(httpClientResponse);
|
||||
});
|
||||
|
||||
final DevFS devFS = DevFS(
|
||||
fakeVmServiceHost.vmService,
|
||||
'test',
|
||||
@ -135,13 +125,12 @@ void main() {
|
||||
osUtils: osUtils,
|
||||
fileSystem: fileSystem,
|
||||
logger: BufferLogger.test(),
|
||||
httpClient: httpClient,
|
||||
httpClient: FakeHttpClient.any(),
|
||||
);
|
||||
expect(() async => await devFS.create(), throwsA(isA<DevFSException>()));
|
||||
});
|
||||
|
||||
testWithoutContext('DevFS destroy is resiliant to vmservice disconnection', () async {
|
||||
final HttpClient httpClient = MockHttpClient();
|
||||
testWithoutContext('DevFS destroy is resilient to vmservice disconnection', () async {
|
||||
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
|
||||
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||
@ -152,15 +141,6 @@ void main() {
|
||||
);
|
||||
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
|
||||
|
||||
final MockHttpClientRequest httpRequest = MockHttpClientRequest();
|
||||
when(httpRequest.headers).thenReturn(MockHttpHeaders());
|
||||
when(httpClient.putUrl(any)).thenAnswer((Invocation invocation) {
|
||||
return Future<HttpClientRequest>.value(httpRequest);
|
||||
});
|
||||
final MockHttpClientResponse httpClientResponse = MockHttpClientResponse();
|
||||
when(httpRequest.close()).thenAnswer((Invocation invocation) {
|
||||
return Future<HttpClientResponse>.value(httpClientResponse);
|
||||
});
|
||||
|
||||
final DevFS devFS = DevFS(
|
||||
fakeVmServiceHost.vmService,
|
||||
@ -169,7 +149,7 @@ void main() {
|
||||
osUtils: osUtils,
|
||||
fileSystem: fileSystem,
|
||||
logger: BufferLogger.test(),
|
||||
httpClient: httpClient,
|
||||
httpClient: FakeHttpClient.any(),
|
||||
);
|
||||
|
||||
expect(await devFS.create(), isNotNull);
|
||||
@ -177,7 +157,6 @@ void main() {
|
||||
});
|
||||
|
||||
testWithoutContext('DevFS retries uploads when connection reset by peer', () async {
|
||||
final HttpClient httpClient = MockHttpClient();
|
||||
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
|
||||
final MockResidentCompiler residentCompiler = MockResidentCompiler();
|
||||
@ -186,21 +165,6 @@ void main() {
|
||||
);
|
||||
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
|
||||
|
||||
final MockHttpClientRequest httpRequest = MockHttpClientRequest();
|
||||
when(httpRequest.headers).thenReturn(MockHttpHeaders());
|
||||
when(httpClient.putUrl(any)).thenAnswer((Invocation invocation) {
|
||||
return Future<HttpClientRequest>.value(httpRequest);
|
||||
});
|
||||
final MockHttpClientResponse httpClientResponse = MockHttpClientResponse();
|
||||
int nRequest = 0;
|
||||
const int kFailedAttempts = 5;
|
||||
when(httpRequest.close()).thenAnswer((Invocation invocation) {
|
||||
if (nRequest++ < kFailedAttempts) {
|
||||
throw const OSError('Connection Reset by peer');
|
||||
}
|
||||
return Future<HttpClientResponse>.value(httpClientResponse);
|
||||
});
|
||||
|
||||
when(residentCompiler.recompile(
|
||||
any,
|
||||
any,
|
||||
@ -220,7 +184,14 @@ void main() {
|
||||
osUtils: osUtils,
|
||||
fileSystem: fileSystem,
|
||||
logger: BufferLogger.test(),
|
||||
httpClient: httpClient,
|
||||
httpClient: FakeHttpClient.list(<FakeRequest>[
|
||||
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, 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)
|
||||
]),
|
||||
uploadRetryThrottle: Duration.zero,
|
||||
);
|
||||
await devFS.create();
|
||||
@ -237,9 +208,7 @@ void main() {
|
||||
|
||||
expect(report.syncedBytes, 5);
|
||||
expect(report.success, isTrue);
|
||||
verify(httpClient.putUrl(any)).called(kFailedAttempts + 1);
|
||||
verify(httpRequest.close()).called(kFailedAttempts + 1);
|
||||
verify(osUtils.gzipLevel1Stream(any)).called(kFailedAttempts + 1);
|
||||
verify(osUtils.gzipLevel1Stream(any)).called(6);
|
||||
});
|
||||
|
||||
testWithoutContext('DevFS reports unsuccessful compile when errors are returned', () async {
|
||||
@ -255,7 +224,7 @@ void main() {
|
||||
fileSystem: fileSystem,
|
||||
logger: BufferLogger.test(),
|
||||
osUtils: FakeOperatingSystemUtils(),
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
);
|
||||
|
||||
await devFS.create();
|
||||
@ -290,16 +259,6 @@ void main() {
|
||||
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||
requests: <VmServiceExpectation>[createDevFSRequest],
|
||||
);
|
||||
final HttpClient httpClient = MockHttpClient();
|
||||
final MockHttpClientRequest httpRequest = MockHttpClientRequest();
|
||||
when(httpRequest.headers).thenReturn(MockHttpHeaders());
|
||||
when(httpClient.putUrl(any)).thenAnswer((Invocation invocation) {
|
||||
return Future<HttpClientRequest>.value(httpRequest);
|
||||
});
|
||||
final MockHttpClientResponse httpClientResponse = MockHttpClientResponse();
|
||||
when(httpRequest.close()).thenAnswer((Invocation invocation) async {
|
||||
return httpClientResponse;
|
||||
});
|
||||
|
||||
final DevFS devFS = DevFS(
|
||||
fakeVmServiceHost.vmService,
|
||||
@ -308,7 +267,7 @@ void main() {
|
||||
fileSystem: fileSystem,
|
||||
logger: BufferLogger.test(),
|
||||
osUtils: FakeOperatingSystemUtils(),
|
||||
httpClient: httpClient,
|
||||
httpClient: FakeHttpClient.any(),
|
||||
);
|
||||
|
||||
await devFS.create();
|
||||
@ -407,7 +366,7 @@ void main() {
|
||||
fileSystem: fileSystem,
|
||||
logger: BufferLogger.test(),
|
||||
osUtils: FakeOperatingSystemUtils(),
|
||||
httpClient: MockHttpClient(),
|
||||
httpClient: FakeHttpClient.any(),
|
||||
);
|
||||
|
||||
await devFS.create();
|
||||
@ -469,9 +428,6 @@ void main() {
|
||||
});
|
||||
}
|
||||
|
||||
class MockHttpClientRequest extends Mock implements HttpClientRequest {}
|
||||
class MockHttpHeaders extends Mock implements HttpHeaders {}
|
||||
class MockHttpClientResponse extends Mock implements HttpClientResponse {}
|
||||
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
|
||||
class MockResidentCompiler extends Mock implements ResidentCompiler {}
|
||||
class MockFile extends Mock implements File {}
|
||||
|
@ -14,6 +14,7 @@ import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/context.dart';
|
||||
import '../src/fake_http_client.dart';
|
||||
import '../src/testbed.dart';
|
||||
|
||||
const String _kShortURL = 'https://www.example.com/short';
|
||||
@ -161,7 +162,14 @@ void main() {
|
||||
final GitHubTemplateCreator creator = GitHubTemplateCreator(
|
||||
fileSystem: fs,
|
||||
logger: logger,
|
||||
client: SuccessShortenURLFakeHttpClient(),
|
||||
client: FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('https://git.io'), method: HttpMethod.post, response: const FakeResponse(
|
||||
statusCode: 201,
|
||||
headers: <String, List<String>>{
|
||||
HttpHeaders.locationHeader: <String>[_kShortURL],
|
||||
}
|
||||
))
|
||||
]),
|
||||
flutterProjectFactory: FlutterProjectFactory(
|
||||
fileSystem: fs,
|
||||
logger: logger,
|
||||
@ -180,7 +188,11 @@ void main() {
|
||||
final GitHubTemplateCreator creator = GitHubTemplateCreator(
|
||||
fileSystem: fs,
|
||||
logger: logger,
|
||||
client: FakeHttpClient(),
|
||||
client: FakeHttpClient.list(<FakeRequest>[
|
||||
FakeRequest(Uri.parse('https://git.io'), method: HttpMethod.post, response: const FakeResponse(
|
||||
statusCode: 500,
|
||||
))
|
||||
]),
|
||||
flutterProjectFactory: FlutterProjectFactory(
|
||||
fileSystem: fs,
|
||||
logger: logger,
|
||||
@ -206,7 +218,7 @@ void main() {
|
||||
final GitHubTemplateCreator creator = GitHubTemplateCreator(
|
||||
fileSystem: fs,
|
||||
logger: logger,
|
||||
client: FakeHttpClient(),
|
||||
client: FakeHttpClient.any(),
|
||||
flutterProjectFactory: FlutterProjectFactory(
|
||||
fileSystem: fs,
|
||||
logger: logger,
|
||||
@ -292,37 +304,7 @@ device_info-0.4.1+4
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
class SuccessFakeHttpHeaders extends FakeHttpHeaders {
|
||||
@override
|
||||
List<String> operator [](String name) => <String>[_kShortURL];
|
||||
}
|
||||
|
||||
class SuccessFakeHttpClientResponse extends FakeHttpClientResponse {
|
||||
@override
|
||||
int get statusCode => 201;
|
||||
|
||||
@override
|
||||
HttpHeaders get headers {
|
||||
return SuccessFakeHttpHeaders();
|
||||
}
|
||||
}
|
||||
|
||||
class SuccessFakeHttpClientRequest extends FakeHttpClientRequest {
|
||||
@override
|
||||
Future<HttpClientResponse> close() async {
|
||||
return SuccessFakeHttpClientResponse();
|
||||
}
|
||||
}
|
||||
|
||||
class SuccessShortenURLFakeHttpClient extends FakeHttpClient {
|
||||
@override
|
||||
Future<HttpClientRequest> postUrl(Uri url) async {
|
||||
return SuccessFakeHttpClientRequest();
|
||||
}
|
||||
}
|
||||
|
||||
class FakeError implements Error {
|
||||
class FakeError extends Error {
|
||||
@override
|
||||
StackTrace get stackTrace => StackTrace.fromString('''
|
||||
#0 _File.open.<anonymous closure> (dart:io/file_impl.dart:366:9)
|
||||
|
@ -69,7 +69,7 @@ void main() {
|
||||
final HttpClientRequest request = await client.getUrl(null);
|
||||
final HttpClientResponse response = await request.close();
|
||||
|
||||
expect(response.statusCode, HttpStatus.badRequest);
|
||||
expect(response.statusCode, HttpStatus.ok);
|
||||
expect(response.contentLength, 0);
|
||||
});
|
||||
});
|
||||
|
@ -37,6 +37,7 @@ import 'package:meta/meta.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'common.dart';
|
||||
import 'fake_http_client.dart';
|
||||
import 'fake_process_manager.dart';
|
||||
import 'fakes.dart';
|
||||
import 'throwing_pub.dart';
|
||||
@ -112,7 +113,7 @@ void testUsingContext(
|
||||
DeviceManager: () => FakeDeviceManager(),
|
||||
Doctor: () => FakeDoctor(globals.logger),
|
||||
FlutterVersion: () => MockFlutterVersion(),
|
||||
HttpClient: () => MockHttpClient(),
|
||||
HttpClient: () => FakeHttpClient.any(),
|
||||
IOSSimulatorUtils: () {
|
||||
final MockIOSSimulatorUtils mock = MockIOSSimulatorUtils();
|
||||
when(mock.getAttachedDevices()).thenAnswer((Invocation _) async => <IOSSimulator>[]);
|
||||
@ -378,8 +379,6 @@ class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter {
|
||||
|
||||
class MockFlutterVersion extends Mock implements FlutterVersion {}
|
||||
|
||||
class MockHttpClient extends Mock implements HttpClient {}
|
||||
|
||||
class MockCrashReporter extends Mock implements CrashReporter {}
|
||||
|
||||
class LocalFileSystemBlockingSetCurrentDirectory extends LocalFileSystem {
|
||||
|
488
packages/flutter_tools/test/src/fake_http_client.dart
Normal file
488
packages/flutter_tools/test/src/fake_http_client.dart
Normal file
@ -0,0 +1,488 @@
|
||||
// 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.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
|
||||
/// The HTTP verb for a [FakeRequest].
|
||||
enum HttpMethod {
|
||||
get,
|
||||
put,
|
||||
delete,
|
||||
post,
|
||||
patch,
|
||||
head,
|
||||
}
|
||||
|
||||
HttpMethod _fromMethodString(String value) {
|
||||
final String name = value.toLowerCase();
|
||||
switch (name) {
|
||||
case 'get':
|
||||
return HttpMethod.get;
|
||||
case 'put':
|
||||
return HttpMethod.put;
|
||||
case 'delete':
|
||||
return HttpMethod.delete;
|
||||
case 'post':
|
||||
return HttpMethod.post;
|
||||
case 'patch':
|
||||
return HttpMethod.patch;
|
||||
case 'head':
|
||||
return HttpMethod.head;
|
||||
default:
|
||||
throw StateError('Unrecognized HTTP method $value');
|
||||
}
|
||||
}
|
||||
|
||||
String _toMethodString(HttpMethod method) {
|
||||
switch (method) {
|
||||
case HttpMethod.get:
|
||||
return 'GET';
|
||||
case HttpMethod.put:
|
||||
return 'PUT';
|
||||
case HttpMethod.delete:
|
||||
return 'DELETE';
|
||||
case HttpMethod.post:
|
||||
return 'POST';
|
||||
case HttpMethod.patch:
|
||||
return 'PATCH';
|
||||
case HttpMethod.head:
|
||||
return 'HEAD';
|
||||
}
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Override the creation of all [HttpClient] objects with a zone injection.
|
||||
///
|
||||
/// This should only be used when the http client cannot be set directly, such as
|
||||
/// when testing `package:http` code.
|
||||
Future<void> overrideHttpClients(Future<void> Function() callback, FakeHttpClient httpClient) async {
|
||||
final HttpOverrides overrides = _FakeHttpClientOverrides(httpClient);
|
||||
await HttpOverrides.runWithHttpOverrides(callback, overrides);
|
||||
}
|
||||
|
||||
class _FakeHttpClientOverrides extends HttpOverrides {
|
||||
_FakeHttpClientOverrides(this.httpClient);
|
||||
|
||||
final FakeHttpClient httpClient;
|
||||
|
||||
@override
|
||||
HttpClient createHttpClient(SecurityContext context) {
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a fake request that configures the [FakeHttpClient] to respond
|
||||
/// with the provided [response].
|
||||
///
|
||||
/// By default, returns a response with a 200 OK status code and an
|
||||
/// empty response. If [responseError] is non-null, will throw this instead
|
||||
/// of returning the response when closing the request.
|
||||
class FakeRequest {
|
||||
const FakeRequest(this.uri, {
|
||||
this.method = HttpMethod.get,
|
||||
this.response = FakeResponse.empty,
|
||||
this.responseError,
|
||||
});
|
||||
|
||||
final Uri uri;
|
||||
final HttpMethod method;
|
||||
final FakeResponse response;
|
||||
final dynamic responseError;
|
||||
|
||||
@override
|
||||
String toString() => 'Request{${_toMethodString(method)}, $uri}';
|
||||
}
|
||||
|
||||
/// The response the server will create for a given [FakeRequest].
|
||||
class FakeResponse {
|
||||
const FakeResponse({
|
||||
this.statusCode = HttpStatus.ok,
|
||||
this.body = const <int>[],
|
||||
this.headers = const <String, List<String>>{},
|
||||
});
|
||||
|
||||
static const FakeResponse empty = FakeResponse();
|
||||
|
||||
final int statusCode;
|
||||
final List<int> body;
|
||||
final Map<String, List<String>> headers;
|
||||
}
|
||||
|
||||
/// A fake implementation of the HttpClient used for testing.
|
||||
///
|
||||
/// This does not fully implement the HttpClient. If an additional method
|
||||
/// is actually needed by the test script, then it should be added here
|
||||
/// instead of in another fake.
|
||||
class FakeHttpClient implements HttpClient {
|
||||
/// Creates an HTTP client that responses to each provided
|
||||
/// fake request with the provided fake response.
|
||||
///
|
||||
/// This does not enforce any order on the requests, but if multiple
|
||||
/// requests match then the first will be selected;
|
||||
FakeHttpClient.list(List<FakeRequest> requests)
|
||||
: _requests = requests.toList();
|
||||
|
||||
/// Creates an HTTP client that always returns an empty 200 request.
|
||||
FakeHttpClient.any() : _any = true, _requests = <FakeRequest>[];
|
||||
|
||||
bool _any = false;
|
||||
final List<FakeRequest> _requests;
|
||||
|
||||
@override
|
||||
bool autoUncompress;
|
||||
|
||||
@override
|
||||
Duration connectionTimeout;
|
||||
|
||||
@override
|
||||
Duration idleTimeout;
|
||||
|
||||
@override
|
||||
int maxConnectionsPerHost;
|
||||
|
||||
@override
|
||||
String userAgent;
|
||||
|
||||
@override
|
||||
void addCredentials(Uri url, String realm, HttpClientCredentials credentials) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void addProxyCredentials(String host, int port, String realm, HttpClientCredentials credentials) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
set authenticate(Future<bool> Function(Uri url, String scheme, String realm) f) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
set authenticateProxy(Future<bool> Function(String host, int port, String scheme, String realm) f) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
set badCertificateCallback(bool Function(X509Certificate cert, String host, int port) callback) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void close({bool force = false}) { }
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> delete(String host, int port, String path) {
|
||||
final Uri uri = Uri(host: host, port: port, path: path);
|
||||
return deleteUrl(uri);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> deleteUrl(Uri url) async {
|
||||
return _findRequest(HttpMethod.delete, url);
|
||||
}
|
||||
|
||||
@override
|
||||
set findProxy(String Function(Uri url) f) { }
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> get(String host, int port, String path) {
|
||||
final Uri uri = Uri(host: host, port: port, path: path);
|
||||
return getUrl(uri);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> getUrl(Uri url) async {
|
||||
return _findRequest(HttpMethod.get, url);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> head(String host, int port, String path) {
|
||||
final Uri uri = Uri(host: host, port: port, path: path);
|
||||
return headUrl(uri);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> headUrl(Uri url) async {
|
||||
return _findRequest(HttpMethod.head, url);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> open(String method, String host, int port, String path) {
|
||||
final Uri uri = Uri(host: host, port: port, path: path);
|
||||
return openUrl(method, uri);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> openUrl(String method, Uri url) async {
|
||||
return _findRequest(_fromMethodString(method), url);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> patch(String host, int port, String path) {
|
||||
final Uri uri = Uri(host: host, port: port, path: path);
|
||||
return patchUrl(uri);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> patchUrl(Uri url) async {
|
||||
return _findRequest(HttpMethod.patch, url);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> post(String host, int port, String path) {
|
||||
final Uri uri = Uri(host: host, port: port, path: path);
|
||||
return postUrl(uri);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> postUrl(Uri url) async {
|
||||
return _findRequest(HttpMethod.post, url);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> put(String host, int port, String path) {
|
||||
final Uri uri = Uri(host: host, port: port, path: path);
|
||||
return putUrl(uri);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> putUrl(Uri url) async {
|
||||
return _findRequest(HttpMethod.put, url);
|
||||
}
|
||||
|
||||
int _requestCount = 0;
|
||||
|
||||
_FakeHttpClientRequest _findRequest(HttpMethod method, Uri uri) {
|
||||
final String methodString = _toMethodString(method);
|
||||
if (_any) {
|
||||
return _FakeHttpClientRequest(
|
||||
FakeResponse.empty,
|
||||
uri,
|
||||
methodString,
|
||||
null,
|
||||
);
|
||||
}
|
||||
FakeRequest matchedRequest;
|
||||
for (final FakeRequest request in _requests) {
|
||||
if (request.method == method && request.uri.toString() == uri.toString()) {
|
||||
matchedRequest = request;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matchedRequest == null) {
|
||||
throw StateError(
|
||||
'Unexpected request for $method to $uri after $_requestCount requests.\n'
|
||||
'Pending requests: ${_requests.join(',')}'
|
||||
);
|
||||
}
|
||||
_requestCount += 1;
|
||||
_requests.remove(matchedRequest);
|
||||
return _FakeHttpClientRequest(
|
||||
matchedRequest.response,
|
||||
uri,
|
||||
methodString,
|
||||
matchedRequest.responseError,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FakeHttpClientRequest implements HttpClientRequest {
|
||||
_FakeHttpClientRequest(this._response, this._uri, this._method, this._responseError);
|
||||
|
||||
final FakeResponse _response;
|
||||
final String _method;
|
||||
final Uri _uri;
|
||||
final dynamic _responseError;
|
||||
|
||||
@override
|
||||
bool bufferOutput;
|
||||
|
||||
@override
|
||||
int contentLength = 0;
|
||||
|
||||
@override
|
||||
Encoding encoding;
|
||||
|
||||
@override
|
||||
bool followRedirects;
|
||||
|
||||
@override
|
||||
int maxRedirects;
|
||||
|
||||
@override
|
||||
bool persistentConnection;
|
||||
|
||||
@override
|
||||
void abort([Object exception, StackTrace stackTrace]) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void add(List<int> data) { }
|
||||
|
||||
@override
|
||||
void addError(Object error, [StackTrace stackTrace]) { }
|
||||
|
||||
@override
|
||||
Future<void> addStream(Stream<List<int>> stream) async { }
|
||||
|
||||
@override
|
||||
Future<HttpClientResponse> close() async {
|
||||
if (_responseError != null) {
|
||||
return Future<HttpClientResponse>.error(_responseError);
|
||||
}
|
||||
return _FakeHttpClientResponse(_response);
|
||||
}
|
||||
|
||||
@override
|
||||
HttpConnectionInfo get connectionInfo => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
List<Cookie> get cookies => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<HttpClientResponse> get done => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<void> flush() async { }
|
||||
|
||||
@override
|
||||
final HttpHeaders headers = _FakeHttpHeaders(<String, List<String>>{});
|
||||
|
||||
@override
|
||||
String get method => _method;
|
||||
|
||||
@override
|
||||
Uri get uri => _uri;
|
||||
|
||||
@override
|
||||
void write(Object object) { }
|
||||
|
||||
@override
|
||||
void writeAll(Iterable<dynamic> objects, [String separator = '']) { }
|
||||
|
||||
@override
|
||||
void writeCharCode(int charCode) { }
|
||||
|
||||
@override
|
||||
void writeln([Object object = '']) { }
|
||||
}
|
||||
|
||||
class _FakeHttpClientResponse extends Stream<List<int>> implements HttpClientResponse {
|
||||
_FakeHttpClientResponse(this._response)
|
||||
: headers = _FakeHttpHeaders(Map<String, List<String>>.from(_response.headers));
|
||||
|
||||
final FakeResponse _response;
|
||||
|
||||
@override
|
||||
X509Certificate get certificate => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
HttpClientResponseCompressionState get compressionState => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
HttpConnectionInfo get connectionInfo => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
int get contentLength => _response.body.length;
|
||||
|
||||
@override
|
||||
List<Cookie> get cookies => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<Socket> detachSocket() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
final HttpHeaders headers;
|
||||
|
||||
@override
|
||||
bool get isRedirect => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
StreamSubscription<List<int>> listen(
|
||||
void Function(List<int> event) onData, {
|
||||
Function onError,
|
||||
void Function() onDone,
|
||||
bool cancelOnError,
|
||||
}) {
|
||||
final Stream<List<int>> response = Stream<List<int>>.fromIterable(<List<int>>[
|
||||
_response.body,
|
||||
]);
|
||||
return response.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get persistentConnection => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
String get reasonPhrase => 'OK';
|
||||
|
||||
@override
|
||||
Future<HttpClientResponse> redirect([String method, Uri url, bool followLoops]) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
List<RedirectInfo> get redirects => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
int get statusCode => _response.statusCode;
|
||||
}
|
||||
|
||||
class _FakeHttpHeaders extends HttpHeaders {
|
||||
_FakeHttpHeaders(this._backingData);
|
||||
|
||||
final Map<String, List<String>> _backingData;
|
||||
|
||||
@override
|
||||
List<String> operator [](String name) => _backingData[name];
|
||||
|
||||
@override
|
||||
void add(String name, Object value, {bool preserveHeaderCase = false}) {
|
||||
_backingData[name] ??= <String>[];
|
||||
_backingData[name].add(value.toString());
|
||||
}
|
||||
|
||||
@override
|
||||
void clear() {
|
||||
_backingData.clear();
|
||||
}
|
||||
|
||||
@override
|
||||
void forEach(void Function(String name, List<String> values) action) { }
|
||||
|
||||
@override
|
||||
void noFolding(String name) { }
|
||||
|
||||
@override
|
||||
void remove(String name, Object value) {
|
||||
_backingData[name]?.remove(value.toString());
|
||||
}
|
||||
|
||||
@override
|
||||
void removeAll(String name) {
|
||||
_backingData.remove(name);
|
||||
}
|
||||
|
||||
@override
|
||||
void set(String name, Object value, {bool preserveHeaderCase = false}) {
|
||||
_backingData[name] = <String>[value.toString()];
|
||||
}
|
||||
|
||||
@override
|
||||
String value(String name) {
|
||||
return _backingData[name]?.join('; ');
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:file/memory.dart';
|
||||
@ -29,6 +28,7 @@ import 'package:process/process.dart';
|
||||
|
||||
import 'common.dart' as tester;
|
||||
import 'context.dart';
|
||||
import 'fake_http_client.dart';
|
||||
import 'throwing_pub.dart';
|
||||
|
||||
export 'package:flutter_tools/src/base/context.dart' show Generator;
|
||||
@ -154,7 +154,7 @@ class Testbed {
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}, createHttpClient: (SecurityContext c) => FakeHttpClient());
|
||||
}, createHttpClient: (SecurityContext c) => FakeHttpClient.any());
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,457 +197,6 @@ class NoOpUsage implements Usage {
|
||||
void sendTiming(String category, String variableName, Duration duration, { String label }) {}
|
||||
}
|
||||
|
||||
class FakeHttpClient implements HttpClient {
|
||||
@override
|
||||
bool autoUncompress;
|
||||
|
||||
@override
|
||||
Duration connectionTimeout;
|
||||
|
||||
@override
|
||||
Duration idleTimeout;
|
||||
|
||||
@override
|
||||
int maxConnectionsPerHost;
|
||||
|
||||
@override
|
||||
String userAgent;
|
||||
|
||||
@override
|
||||
void addCredentials(Uri url, String realm, HttpClientCredentials credentials) {}
|
||||
|
||||
@override
|
||||
void addProxyCredentials(String host, int port, String realm, HttpClientCredentials credentials) {}
|
||||
|
||||
@override
|
||||
set authenticate(Future<bool> Function(Uri url, String scheme, String realm) f) {}
|
||||
|
||||
@override
|
||||
set authenticateProxy(Future<bool> Function(String host, int port, String scheme, String realm) f) {}
|
||||
|
||||
@override
|
||||
set badCertificateCallback(bool Function(X509Certificate cert, String host, int port) callback) {}
|
||||
|
||||
@override
|
||||
void close({bool force = false}) {}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> delete(String host, int port, String path) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> deleteUrl(Uri url) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
set findProxy(String Function(Uri url) f) {}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> get(String host, int port, String path) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> getUrl(Uri url) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> head(String host, int port, String path) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> headUrl(Uri url) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> open(String method, String host, int port, String path) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> openUrl(String method, Uri url) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> patch(String host, int port, String path) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> patchUrl(Uri url) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> post(String host, int port, String path) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> postUrl(Uri url) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> put(String host, int port, String path) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> putUrl(Uri url) async {
|
||||
return FakeHttpClientRequest();
|
||||
}
|
||||
}
|
||||
|
||||
class FakeHttpClientRequest implements HttpClientRequest {
|
||||
FakeHttpClientRequest();
|
||||
|
||||
@override
|
||||
bool bufferOutput;
|
||||
|
||||
@override
|
||||
int contentLength;
|
||||
|
||||
@override
|
||||
Encoding encoding;
|
||||
|
||||
@override
|
||||
bool followRedirects;
|
||||
|
||||
@override
|
||||
int maxRedirects;
|
||||
|
||||
@override
|
||||
bool persistentConnection;
|
||||
|
||||
@override
|
||||
void add(List<int> data) {}
|
||||
|
||||
@override
|
||||
void addError(Object error, [StackTrace stackTrace]) {}
|
||||
|
||||
@override
|
||||
Future<void> addStream(Stream<List<int>> stream) async {}
|
||||
|
||||
@override
|
||||
Future<HttpClientResponse> close() async {
|
||||
return FakeHttpClientResponse();
|
||||
}
|
||||
|
||||
@override
|
||||
HttpConnectionInfo get connectionInfo => null;
|
||||
|
||||
@override
|
||||
List<Cookie> get cookies => <Cookie>[];
|
||||
|
||||
@override
|
||||
Future<HttpClientResponse> get done => null;
|
||||
|
||||
@override
|
||||
Future<void> flush() {
|
||||
return Future<void>.value();
|
||||
}
|
||||
|
||||
@override
|
||||
HttpHeaders get headers => FakeHttpHeaders();
|
||||
|
||||
@override
|
||||
String get method => null;
|
||||
|
||||
@override
|
||||
Uri get uri => null;
|
||||
|
||||
@override
|
||||
void write(Object obj) {}
|
||||
|
||||
@override
|
||||
void writeAll(Iterable<Object> objects, [String separator = '']) {}
|
||||
|
||||
@override
|
||||
void writeCharCode(int charCode) {}
|
||||
|
||||
@override
|
||||
void writeln([Object obj = '']) {}
|
||||
|
||||
// TODO(zichangguo): remove the ignore after the change in dart:io lands.
|
||||
@override
|
||||
// ignore: override_on_non_overriding_member
|
||||
void abort([Object exception, StackTrace stackTrace]) {}
|
||||
}
|
||||
|
||||
class FakeHttpClientResponse implements HttpClientResponse {
|
||||
final Stream<List<int>> _delegate = Stream<List<int>>.fromIterable(const Iterable<List<int>>.empty());
|
||||
|
||||
@override
|
||||
final HttpHeaders headers = FakeHttpHeaders();
|
||||
|
||||
@override
|
||||
X509Certificate get certificate => null;
|
||||
|
||||
@override
|
||||
HttpConnectionInfo get connectionInfo => null;
|
||||
|
||||
@override
|
||||
int get contentLength => 0;
|
||||
|
||||
@override
|
||||
HttpClientResponseCompressionState get compressionState {
|
||||
return HttpClientResponseCompressionState.decompressed;
|
||||
}
|
||||
|
||||
@override
|
||||
List<Cookie> get cookies => null;
|
||||
|
||||
@override
|
||||
Future<Socket> detachSocket() {
|
||||
return Future<Socket>.error(UnsupportedError('Mocked response'));
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isRedirect => false;
|
||||
|
||||
@override
|
||||
StreamSubscription<List<int>> listen(void Function(List<int> event) onData, { Function onError, void Function() onDone, bool cancelOnError }) {
|
||||
return const Stream<List<int>>.empty().listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get persistentConnection => null;
|
||||
|
||||
@override
|
||||
String get reasonPhrase => null;
|
||||
|
||||
@override
|
||||
Future<HttpClientResponse> redirect([ String method, Uri url, bool followLoops ]) {
|
||||
return Future<HttpClientResponse>.error(UnsupportedError('Mocked response'));
|
||||
}
|
||||
|
||||
@override
|
||||
List<RedirectInfo> get redirects => <RedirectInfo>[];
|
||||
|
||||
@override
|
||||
int get statusCode => 400;
|
||||
|
||||
@override
|
||||
Future<bool> any(bool Function(List<int> element) test) {
|
||||
return _delegate.any(test);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<int>> asBroadcastStream({
|
||||
void Function(StreamSubscription<List<int>> subscription) onListen,
|
||||
void Function(StreamSubscription<List<int>> subscription) onCancel,
|
||||
}) {
|
||||
return _delegate.asBroadcastStream(onListen: onListen, onCancel: onCancel);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<E> asyncExpand<E>(Stream<E> Function(List<int> event) convert) {
|
||||
return _delegate.asyncExpand<E>(convert);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<E> asyncMap<E>(FutureOr<E> Function(List<int> event) convert) {
|
||||
return _delegate.asyncMap<E>(convert);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<R> cast<R>() {
|
||||
return _delegate.cast<R>();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> contains(Object needle) {
|
||||
return _delegate.contains(needle);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<int>> distinct([bool Function(List<int> previous, List<int> next) equals]) {
|
||||
return _delegate.distinct(equals);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<E> drain<E>([E futureValue]) {
|
||||
return _delegate.drain<E>(futureValue);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<int>> elementAt(int index) {
|
||||
return _delegate.elementAt(index);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> every(bool Function(List<int> element) test) {
|
||||
return _delegate.every(test);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<S> expand<S>(Iterable<S> Function(List<int> element) convert) {
|
||||
return _delegate.expand(convert);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<int>> get first => _delegate.first;
|
||||
|
||||
@override
|
||||
Future<List<int>> firstWhere(
|
||||
bool Function(List<int> element) test, {
|
||||
List<int> Function() orElse,
|
||||
}) {
|
||||
return _delegate.firstWhere(test, orElse: orElse);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<S> fold<S>(S initialValue, S Function(S previous, List<int> element) combine) {
|
||||
return _delegate.fold<S>(initialValue, combine);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<dynamic> forEach(void Function(List<int> element) action) {
|
||||
return _delegate.forEach(action);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<int>> handleError(
|
||||
Function onError, {
|
||||
bool Function(dynamic error) test,
|
||||
}) {
|
||||
return _delegate.handleError(onError, test: test);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isBroadcast => _delegate.isBroadcast;
|
||||
|
||||
@override
|
||||
Future<bool> get isEmpty => _delegate.isEmpty;
|
||||
|
||||
@override
|
||||
Future<String> join([String separator = '']) {
|
||||
return _delegate.join(separator);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<int>> get last => _delegate.last;
|
||||
|
||||
@override
|
||||
Future<List<int>> lastWhere(
|
||||
bool Function(List<int> element) test, {
|
||||
List<int> Function() orElse,
|
||||
}) {
|
||||
return _delegate.lastWhere(test, orElse: orElse);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> get length => _delegate.length;
|
||||
|
||||
@override
|
||||
Stream<S> map<S>(S Function(List<int> event) convert) {
|
||||
return _delegate.map<S>(convert);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<dynamic> pipe(StreamConsumer<List<int>> streamConsumer) {
|
||||
return _delegate.pipe(streamConsumer);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<int>> reduce(List<int> Function(List<int> previous, List<int> element) combine) {
|
||||
return _delegate.reduce(combine);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<int>> get single => _delegate.single;
|
||||
|
||||
@override
|
||||
Future<List<int>> singleWhere(bool Function(List<int> element) test, {List<int> Function() orElse}) {
|
||||
return _delegate.singleWhere(test, orElse: orElse);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<int>> skip(int count) {
|
||||
return _delegate.skip(count);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<int>> skipWhile(bool Function(List<int> element) test) {
|
||||
return _delegate.skipWhile(test);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<int>> take(int count) {
|
||||
return _delegate.take(count);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<int>> takeWhile(bool Function(List<int> element) test) {
|
||||
return _delegate.takeWhile(test);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<int>> timeout(
|
||||
Duration timeLimit, {
|
||||
void Function(EventSink<List<int>> sink) onTimeout,
|
||||
}) {
|
||||
return _delegate.timeout(timeLimit, onTimeout: onTimeout);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<List<int>>> toList() {
|
||||
return _delegate.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Set<List<int>>> toSet() {
|
||||
return _delegate.toSet();
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<S> transform<S>(StreamTransformer<List<int>, S> streamTransformer) {
|
||||
return _delegate.transform<S>(streamTransformer);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<int>> where(bool Function(List<int> event) test) {
|
||||
return _delegate.where(test);
|
||||
}
|
||||
}
|
||||
|
||||
/// A fake [HttpHeaders] that ignores all writes.
|
||||
class FakeHttpHeaders extends HttpHeaders {
|
||||
@override
|
||||
List<String> operator [](String name) => <String>[];
|
||||
|
||||
@override
|
||||
void add(String name, Object value, {bool preserveHeaderCase = false}) { }
|
||||
|
||||
@override
|
||||
void clear() { }
|
||||
|
||||
@override
|
||||
void forEach(void Function(String name, List<String> values) f) { }
|
||||
|
||||
@override
|
||||
void noFolding(String name) { }
|
||||
|
||||
@override
|
||||
void remove(String name, Object value) { }
|
||||
|
||||
@override
|
||||
void removeAll(String name) { }
|
||||
|
||||
@override
|
||||
void set(String name, Object value, {bool preserveHeaderCase = false}) { }
|
||||
|
||||
@override
|
||||
String value(String name) => null;
|
||||
}
|
||||
|
||||
class FakeFlutterVersion implements FlutterVersion {
|
||||
@override
|
||||
void fetchTagsAndUpdate() { }
|
||||
|
Loading…
Reference in New Issue
Block a user