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, {
|
Future<List<int>> fetchUrl(Uri url, {
|
||||||
int maxAttempts,
|
int maxAttempts,
|
||||||
File destFile,
|
File destFile,
|
||||||
|
@visibleForTesting Duration durationOverride,
|
||||||
}) async {
|
}) async {
|
||||||
int attempts = 0;
|
int attempts = 0;
|
||||||
int durationSeconds = 1;
|
int durationSeconds = 1;
|
||||||
@ -78,7 +79,7 @@ class Net {
|
|||||||
'Download failed -- attempting retry $attempts in '
|
'Download failed -- attempting retry $attempts in '
|
||||||
'$durationSeconds second${ durationSeconds == 1 ? "" : "s"}...',
|
'$durationSeconds second${ durationSeconds == 1 ? "" : "s"}...',
|
||||||
);
|
);
|
||||||
await Future<void>.delayed(Duration(seconds: durationSeconds));
|
await Future<void>.delayed(durationOverride ?? Duration(seconds: durationSeconds));
|
||||||
if (durationSeconds < 64) {
|
if (durationSeconds < 64) {
|
||||||
durationSeconds *= 2;
|
durationSeconds *= 2;
|
||||||
}
|
}
|
||||||
@ -173,8 +174,6 @@ class Net {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// An IOSink that collects whatever is written to it.
|
/// An IOSink that collects whatever is written to it.
|
||||||
class _MemoryIOSink implements IOSink {
|
class _MemoryIOSink implements IOSink {
|
||||||
@override
|
@override
|
||||||
|
@ -78,7 +78,6 @@ void main() {
|
|||||||
MockPortForwarder portForwarder;
|
MockPortForwarder portForwarder;
|
||||||
MockDartDevelopmentService mockDds;
|
MockDartDevelopmentService mockDds;
|
||||||
MockAndroidDevice device;
|
MockAndroidDevice device;
|
||||||
MockHttpClient httpClient;
|
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
fakeLogReader = FakeDeviceLogReader();
|
fakeLogReader = FakeDeviceLogReader();
|
||||||
@ -98,13 +97,6 @@ void main() {
|
|||||||
when(mockDds.startDartDevelopmentService(any, any, false, any)).thenReturn(null);
|
when(mockDds.startDartDevelopmentService(any, any, false, any)).thenReturn(null);
|
||||||
when(mockDds.uri).thenReturn(Uri.parse('http://localhost:8181'));
|
when(mockDds.uri).thenReturn(Uri.parse('http://localhost:8181'));
|
||||||
when(mockDds.done).thenAnswer((_) => noopCompleter.future);
|
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
|
// We cannot add the device to a device manager because that is
|
||||||
// only enabled by the context of each testUsingContext call.
|
// only enabled by the context of each testUsingContext call.
|
||||||
@ -925,6 +917,3 @@ class TestHotRunnerFactory extends HotRunnerFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MockDartDevelopmentService extends Mock implements DartDevelopmentService {}
|
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:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:args/command_runner.dart';
|
import 'package:args/command_runner.dart';
|
||||||
import 'package:file_testing/file_testing.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/common.dart';
|
||||||
import '../../src/context.dart';
|
import '../../src/context.dart';
|
||||||
|
import '../../src/fake_http_client.dart';
|
||||||
import '../../src/pubspec_schema.dart';
|
import '../../src/pubspec_schema.dart';
|
||||||
import '../../src/testbed.dart';
|
import '../../src/testbed.dart';
|
||||||
|
|
||||||
@ -1627,7 +1627,16 @@ void main() {
|
|||||||
expect(projectDir.childDirectory('lib').childFile('main.dart').readAsStringSync(),
|
expect(projectDir.childDirectory('lib').childFile('main.dart').readAsStringSync(),
|
||||||
contains('void main() {}'));
|
contains('void main() {}'));
|
||||||
}, overrides: <Type, Generator>{
|
}, 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 {
|
testUsingContext('null-safe sample-based project have no analyzer errors', () async {
|
||||||
@ -1641,7 +1650,16 @@ void main() {
|
|||||||
contains('String?'), // uses null-safe syntax
|
contains('String?'), // uses null-safe syntax
|
||||||
);
|
);
|
||||||
}, overrides: <Type, Generator>{
|
}, 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 {
|
testUsingContext('can write samples index to disk', () async {
|
||||||
@ -1659,8 +1677,16 @@ void main() {
|
|||||||
expect(expectedFile, exists);
|
expect(expectedFile, exists);
|
||||||
expect(expectedFile.readAsStringSync(), equals(samplesIndexJson));
|
expect(expectedFile.readAsStringSync(), equals(samplesIndexJson));
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
HttpClientFactory: () =>
|
HttpClientFactory: () {
|
||||||
() => MockHttpClient(200, result: samplesIndexJson),
|
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 {
|
testUsingContext('Throws tool exit on empty samples index', () async {
|
||||||
@ -1680,8 +1706,15 @@ void main() {
|
|||||||
message: 'Unable to download samples',
|
message: 'Unable to download samples',
|
||||||
));
|
));
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
HttpClientFactory: () =>
|
HttpClientFactory: () {
|
||||||
() => MockHttpClient(200, result: ''),
|
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 {
|
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'));
|
await expectLater(runner.run(args), throwsToolExit(exitCode: 2, message: 'Failed to write samples'));
|
||||||
expect(globals.fs.file(outputFile), isNot(exists));
|
expect(globals.fs.file(outputFile), isNot(exists));
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
HttpClientFactory: () =>
|
HttpClientFactory: () {
|
||||||
() => MockHttpClient(404, result: 'not found'),
|
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 {
|
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 'package:mockito/mockito.dart';
|
||||||
|
|
||||||
import '../src/common.dart';
|
import '../src/common.dart';
|
||||||
|
import '../src/fake_http_client.dart';
|
||||||
import '../src/fakes.dart';
|
import '../src/fakes.dart';
|
||||||
|
|
||||||
final Platform testPlatform = FakePlatform(environment: const <String, String>{});
|
final Platform testPlatform = FakePlatform(environment: const <String, String>{});
|
||||||
@ -32,7 +33,7 @@ void main() {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
platform: testPlatform,
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -55,7 +56,7 @@ void main() {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
platform: testPlatform,
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -80,17 +81,19 @@ void main() {
|
|||||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final BufferLogger logger = BufferLogger.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(
|
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
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')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -109,20 +112,23 @@ void main() {
|
|||||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final BufferLogger logger = BufferLogger.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(
|
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
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')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -141,20 +147,31 @@ void main() {
|
|||||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final BufferLogger logger = BufferLogger.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(
|
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
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')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -179,7 +196,10 @@ void main() {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
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')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -197,14 +217,16 @@ void main() {
|
|||||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final BufferLogger logger = BufferLogger.test();
|
final BufferLogger logger = BufferLogger.test();
|
||||||
final MockHttpClient client = MockHttpClient();
|
|
||||||
client.testRequest.testResponse.statusCode = HttpStatus.preconditionFailed;
|
|
||||||
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
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')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -215,7 +237,6 @@ void main() {
|
|||||||
fileSystem.currentDirectory.childDirectory('out'),
|
fileSystem.currentDirectory.childDirectory('out'),
|
||||||
), throwsToolExit());
|
), throwsToolExit());
|
||||||
|
|
||||||
expect(client.attempts, 2);
|
|
||||||
expect(logger.statusText, contains('test message'));
|
expect(logger.statusText, contains('test message'));
|
||||||
expect(fileSystem.file('out/test'), isNot(exists));
|
expect(fileSystem.file('out/test'), isNot(exists));
|
||||||
});
|
});
|
||||||
@ -224,8 +245,6 @@ void main() {
|
|||||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final BufferLogger logger = BufferLogger.test();
|
final BufferLogger logger = BufferLogger.test();
|
||||||
final MockHttpClient client = MockHttpClient();
|
|
||||||
client.argumentError = true;
|
|
||||||
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
@ -235,7 +254,9 @@ void main() {
|
|||||||
'FLUTTER_STORAGE_BASE_URL': 'foo-bar'
|
'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')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -246,7 +267,6 @@ void main() {
|
|||||||
fileSystem.currentDirectory.childDirectory('out'),
|
fileSystem.currentDirectory.childDirectory('out'),
|
||||||
), throwsToolExit());
|
), throwsToolExit());
|
||||||
|
|
||||||
expect(client.attempts, 1);
|
|
||||||
expect(logger.statusText, contains('test message'));
|
expect(logger.statusText, contains('test message'));
|
||||||
expect(fileSystem.file('out/test'), isNot(exists));
|
expect(fileSystem.file('out/test'), isNot(exists));
|
||||||
});
|
});
|
||||||
@ -255,14 +275,14 @@ void main() {
|
|||||||
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
final MockOperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
|
||||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final BufferLogger logger = BufferLogger.test();
|
final BufferLogger logger = BufferLogger.test();
|
||||||
final MockHttpClient client = MockHttpClient();
|
|
||||||
client.argumentError = true;
|
|
||||||
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
platform: testPlatform,
|
||||||
httpClient: client,
|
httpClient: FakeHttpClient.list(<FakeRequest>[
|
||||||
|
FakeRequest(Uri.parse('http:///test.zip'), responseError: ArgumentError()),
|
||||||
|
]),
|
||||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -273,7 +293,6 @@ void main() {
|
|||||||
fileSystem.currentDirectory.childDirectory('out'),
|
fileSystem.currentDirectory.childDirectory('out'),
|
||||||
), throwsA(isA<ArgumentError>()));
|
), throwsA(isA<ArgumentError>()));
|
||||||
|
|
||||||
expect(client.attempts, 1);
|
|
||||||
expect(logger.statusText, contains('test message'));
|
expect(logger.statusText, contains('test message'));
|
||||||
expect(fileSystem.file('out/test'), isNot(exists));
|
expect(fileSystem.file('out/test'), isNot(exists));
|
||||||
});
|
});
|
||||||
@ -287,7 +306,7 @@ void main() {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
platform: testPlatform,
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -311,7 +330,7 @@ void main() {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
platform: testPlatform,
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -335,7 +354,7 @@ void main() {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
platform: testPlatform,
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -359,7 +378,7 @@ void main() {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
platform: testPlatform,
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -383,7 +402,7 @@ void main() {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
platform: testPlatform,
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -405,7 +424,7 @@ void main() {
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
platform: testPlatform,
|
platform: testPlatform,
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
|
||||||
..createSync(),
|
..createSync(),
|
||||||
);
|
);
|
||||||
@ -448,57 +467,3 @@ class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {
|
|||||||
.createSync();
|
.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
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/base/bot_detector.dart';
|
import 'package:flutter_tools/src/base/bot_detector.dart';
|
||||||
import 'package:flutter_tools/src/base/io.dart';
|
import 'package:flutter_tools/src/base/io.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/base/platform.dart';
|
import 'package:flutter_tools/src/base/platform.dart';
|
||||||
import 'package:flutter_tools/src/persistent_tool_state.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/common.dart';
|
||||||
|
import '../../src/fake_http_client.dart';
|
||||||
import '../../src/fakes.dart';
|
import '../../src/fakes.dart';
|
||||||
|
|
||||||
|
final Uri azureUrl = Uri.parse('http://169.254.169.254/metadata/instance');
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('BotDetector', () {
|
group('BotDetector', () {
|
||||||
FakePlatform fakePlatform;
|
FakePlatform fakePlatform;
|
||||||
FakeStdio fakeStdio;
|
FakeStdio fakeStdio;
|
||||||
MockHttpClient mockHttpClient;
|
|
||||||
MockHttpClientRequest mockHttpClientRequest;
|
|
||||||
MockHttpHeaders mockHttpHeaders;
|
|
||||||
BotDetector botDetector;
|
|
||||||
PersistentToolState persistentToolState;
|
PersistentToolState persistentToolState;
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
fakePlatform = FakePlatform()..environment = <String, String>{};
|
fakePlatform = FakePlatform()..environment = <String, String>{};
|
||||||
fakeStdio = FakeStdio();
|
fakeStdio = FakeStdio();
|
||||||
mockHttpClient = MockHttpClient();
|
|
||||||
mockHttpClientRequest = MockHttpClientRequest();
|
|
||||||
mockHttpHeaders = MockHttpHeaders();
|
|
||||||
persistentToolState = PersistentToolState.test(
|
persistentToolState = PersistentToolState.test(
|
||||||
directory: MemoryFileSystem.test().currentDirectory,
|
directory: MemoryFileSystem.test().currentDirectory,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
);
|
);
|
||||||
botDetector = BotDetector(
|
|
||||||
platform: fakePlatform,
|
|
||||||
httpClientFactory: () => mockHttpClient,
|
|
||||||
persistentToolState: persistentToolState,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
group('isRunningOnBot', () {
|
group('isRunningOnBot', () {
|
||||||
@ -50,6 +37,12 @@ void main() {
|
|||||||
fakePlatform.environment['BOT'] = 'false';
|
fakePlatform.environment['BOT'] = 'false';
|
||||||
fakePlatform.environment['TRAVIS'] = 'true';
|
fakePlatform.environment['TRAVIS'] = 'true';
|
||||||
|
|
||||||
|
final BotDetector botDetector = BotDetector(
|
||||||
|
platform: fakePlatform,
|
||||||
|
httpClientFactory: () => FakeHttpClient.any(),
|
||||||
|
persistentToolState: persistentToolState,
|
||||||
|
);
|
||||||
|
|
||||||
expect(await botDetector.isRunningOnBot, isFalse);
|
expect(await botDetector.isRunningOnBot, isFalse);
|
||||||
expect(persistentToolState.isRunningOnBot, isFalse);
|
expect(persistentToolState.isRunningOnBot, isFalse);
|
||||||
});
|
});
|
||||||
@ -58,14 +51,25 @@ void main() {
|
|||||||
fakePlatform.environment['FLUTTER_HOST'] = 'foo';
|
fakePlatform.environment['FLUTTER_HOST'] = 'foo';
|
||||||
fakePlatform.environment['TRAVIS'] = 'true';
|
fakePlatform.environment['TRAVIS'] = 'true';
|
||||||
|
|
||||||
|
final BotDetector botDetector = BotDetector(
|
||||||
|
platform: fakePlatform,
|
||||||
|
httpClientFactory: () => FakeHttpClient.any(),
|
||||||
|
persistentToolState: persistentToolState,
|
||||||
|
);
|
||||||
|
|
||||||
expect(await botDetector.isRunningOnBot, isFalse);
|
expect(await botDetector.isRunningOnBot, isFalse);
|
||||||
expect(persistentToolState.isRunningOnBot, isFalse);
|
expect(persistentToolState.isRunningOnBot, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('returns false with and without a terminal attached', () async {
|
testWithoutContext('returns false with and without a terminal attached', () async {
|
||||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
final BotDetector botDetector = BotDetector(
|
||||||
throw const SocketException('HTTP connection timed out');
|
platform: fakePlatform,
|
||||||
});
|
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[
|
||||||
|
FakeRequest(azureUrl, responseError: const SocketException('HTTP connection timed out')),
|
||||||
|
]),
|
||||||
|
persistentToolState: persistentToolState,
|
||||||
|
);
|
||||||
|
|
||||||
fakeStdio.stdout.hasTerminal = true;
|
fakeStdio.stdout.hasTerminal = true;
|
||||||
expect(await botDetector.isRunningOnBot, isFalse);
|
expect(await botDetector.isRunningOnBot, isFalse);
|
||||||
fakeStdio.stdout.hasTerminal = false;
|
fakeStdio.stdout.hasTerminal = false;
|
||||||
@ -76,38 +80,52 @@ void main() {
|
|||||||
testWithoutContext('can test analytics outputs on bots when outputting to a file', () async {
|
testWithoutContext('can test analytics outputs on bots when outputting to a file', () async {
|
||||||
fakePlatform.environment['TRAVIS'] = 'true';
|
fakePlatform.environment['TRAVIS'] = 'true';
|
||||||
fakePlatform.environment['FLUTTER_ANALYTICS_LOG_FILE'] = '/some/file';
|
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(await botDetector.isRunningOnBot, isFalse);
|
||||||
expect(persistentToolState.isRunningOnBot, isFalse);
|
expect(persistentToolState.isRunningOnBot, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('returns true when azure metadata is reachable', () async {
|
testWithoutContext('returns true when azure metadata is reachable', () async {
|
||||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
final BotDetector botDetector = BotDetector(
|
||||||
return Future<HttpClientRequest>.value(mockHttpClientRequest);
|
platform: fakePlatform,
|
||||||
});
|
httpClientFactory: () => FakeHttpClient.any(),
|
||||||
when(mockHttpClientRequest.headers).thenReturn(mockHttpHeaders);
|
persistentToolState: persistentToolState,
|
||||||
|
);
|
||||||
|
|
||||||
expect(await botDetector.isRunningOnBot, isTrue);
|
expect(await botDetector.isRunningOnBot, isTrue);
|
||||||
expect(persistentToolState.isRunningOnBot, isTrue);
|
expect(persistentToolState.isRunningOnBot, isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('caches azure bot detection results across instances', () async {
|
testWithoutContext('caches azure bot detection results across instances', () async {
|
||||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
final BotDetector botDetector = BotDetector(
|
||||||
return Future<HttpClientRequest>.value(mockHttpClientRequest);
|
platform: fakePlatform,
|
||||||
});
|
httpClientFactory: () => FakeHttpClient.any(),
|
||||||
when(mockHttpClientRequest.headers).thenReturn(mockHttpHeaders);
|
persistentToolState: persistentToolState,
|
||||||
|
);
|
||||||
|
|
||||||
expect(await botDetector.isRunningOnBot, isTrue);
|
expect(await botDetector.isRunningOnBot, isTrue);
|
||||||
expect(await BotDetector(
|
expect(await BotDetector(
|
||||||
platform: fakePlatform,
|
platform: fakePlatform,
|
||||||
httpClientFactory: () => mockHttpClient,
|
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[]),
|
||||||
persistentToolState: persistentToolState,
|
persistentToolState: persistentToolState,
|
||||||
).isRunningOnBot, isTrue);
|
).isRunningOnBot, isTrue);
|
||||||
verify(mockHttpClient.getUrl(any)).called(1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('returns true when running on borg', () async {
|
testWithoutContext('returns true when running on borg', () async {
|
||||||
fakePlatform.environment['BORG_ALLOC_DIR'] = 'true';
|
fakePlatform.environment['BORG_ALLOC_DIR'] = 'true';
|
||||||
|
|
||||||
|
final BotDetector botDetector = BotDetector(
|
||||||
|
platform: fakePlatform,
|
||||||
|
httpClientFactory: () => FakeHttpClient.any(),
|
||||||
|
persistentToolState: persistentToolState,
|
||||||
|
);
|
||||||
|
|
||||||
expect(await botDetector.isRunningOnBot, isTrue);
|
expect(await botDetector.isRunningOnBot, isTrue);
|
||||||
expect(persistentToolState.isRunningOnBot, isTrue);
|
expect(persistentToolState.isRunningOnBot, isTrue);
|
||||||
});
|
});
|
||||||
@ -115,60 +133,34 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
group('AzureDetector', () {
|
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 {
|
testWithoutContext('isRunningOnAzure returns false when connection times out', () async {
|
||||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
final AzureDetector azureDetector = AzureDetector(
|
||||||
throw const SocketException('HTTP connection timed out');
|
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[
|
||||||
});
|
FakeRequest(azureUrl, responseError: const SocketException('HTTP connection timed out')),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
|
||||||
expect(await azureDetector.isRunningOnAzure, isFalse);
|
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 {
|
testWithoutContext('isRunningOnAzure returns false when OsError is thrown', () async {
|
||||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
final AzureDetector azureDetector = AzureDetector(
|
||||||
throw const OSError('Connection Refused', 111);
|
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[
|
||||||
});
|
FakeRequest(azureUrl, responseError: const OSError('Connection Refused', 111)),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
|
||||||
expect(await azureDetector.isRunningOnAzure, isFalse);
|
expect(await azureDetector.isRunningOnAzure, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('isRunningOnAzure returns true when azure metadata is reachable', () async {
|
testWithoutContext('isRunningOnAzure returns true when azure metadata is reachable', () async {
|
||||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
final AzureDetector azureDetector = AzureDetector(
|
||||||
return Future<HttpClientRequest>.value(mockHttpClientRequest);
|
httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[
|
||||||
});
|
FakeRequest(azureUrl),
|
||||||
when(mockHttpClientRequest.headers).thenReturn(mockHttpHeaders);
|
],
|
||||||
|
));
|
||||||
|
|
||||||
expect(await azureDetector.isRunningOnAzure, isTrue);
|
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
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:file/file.dart';
|
import 'package:file/file.dart';
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/base/file_system.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' as io;
|
||||||
|
import 'package:flutter_tools/src/base/io.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/base/net.dart';
|
import 'package:flutter_tools/src/base/net.dart';
|
||||||
import 'package:flutter_tools/src/base/platform.dart';
|
import 'package:flutter_tools/src/base/platform.dart';
|
||||||
import 'package:fake_async/fake_async.dart';
|
import 'package:fake_async/fake_async.dart';
|
||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
|
import '../../src/fake_http_client.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
BufferLogger testLogger;
|
BufferLogger testLogger;
|
||||||
@ -42,75 +43,93 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('fetchUrl() gets the data', () async {
|
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/'));
|
final List<int> data = await net.fetchUrl(Uri.parse('http://example.invalid/'));
|
||||||
expect(data, equals(responseData));
|
expect(data, equals(responseData));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('fetchUrl(destFile) writes the data to a file', () async {
|
testWithoutContext('fetchUrl(destFile) writes the data to a file', () async {
|
||||||
final Net net = createNet(FakeHttpClient(200, data: responseString));
|
final Net net = createNet(
|
||||||
final MemoryFileSystem fs = MemoryFileSystem.test();
|
FakeHttpClient.list(<FakeRequest>[
|
||||||
final File destFile = fs.file('dest_file')..createSync();
|
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(
|
final List<int> data = await net.fetchUrl(
|
||||||
Uri.parse('http://example.invalid/'),
|
Uri.parse('http://example.invalid/'),
|
||||||
destFile: destFile,
|
destFile: destFile,
|
||||||
);
|
);
|
||||||
expect(data, equals(<int>[]));
|
expect(data, equals(<int>[]));
|
||||||
expect(destFile.readAsStringSync(), equals(responseString));
|
expect(destFile.readAsStringSync(), responseString);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('retry from 500', () async {
|
testWithoutContext('retry from 500', () async {
|
||||||
final Net net = createNet(FakeHttpClient(500));
|
final Net net = createNet(
|
||||||
String error;
|
FakeHttpClient.list(<FakeRequest>[
|
||||||
FakeAsync().run((FakeAsync time) {
|
FakeRequest(Uri.parse('http://example.invalid/'), response: const FakeResponse(statusCode: io.HttpStatus.internalServerError)),
|
||||||
net.fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
FakeRequest(Uri.parse('http://example.invalid/'), response: const FakeResponse(statusCode: io.HttpStatus.internalServerError)),
|
||||||
error = 'test completed unexpectedly';
|
FakeRequest(Uri.parse('http://example.invalid/'), response: const FakeResponse(statusCode: io.HttpStatus.internalServerError)),
|
||||||
}, onError: (dynamic exception) {
|
FakeRequest(Uri.parse('http://example.invalid/'), response: const FakeResponse(statusCode: io.HttpStatus.internalServerError)),
|
||||||
error = 'test failed unexpectedly: $exception';
|
])
|
||||||
});
|
);
|
||||||
expect(testLogger.statusText, '');
|
|
||||||
time.elapse(const Duration(milliseconds: 10000));
|
await net.fetchUrl(Uri.parse('http://example.invalid/'), maxAttempts: 4, durationOverride: Duration.zero);
|
||||||
|
|
||||||
expect(testLogger.statusText,
|
expect(testLogger.statusText,
|
||||||
'Download failed -- attempting retry 1 in 1 second...\n'
|
'Download failed -- attempting retry 1 in 1 second...\n'
|
||||||
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
||||||
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
||||||
'Download failed -- attempting retry 4 in 8 seconds...\n',
|
'Download failed -- retry 4\n',
|
||||||
);
|
);
|
||||||
});
|
|
||||||
expect(testLogger.errorText, isEmpty);
|
expect(testLogger.errorText, isEmpty);
|
||||||
expect(error, isNull);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('retry from network error', () async {
|
testWithoutContext('retry from network error', () async {
|
||||||
final Net net = createNet(FakeHttpClient(200));
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||||
String error;
|
final Net net = createNet(
|
||||||
FakeAsync().run((FakeAsync time) {
|
FakeHttpClient.list(<FakeRequest>[
|
||||||
net.fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
||||||
error = 'test completed unexpectedly';
|
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
||||||
}, onError: (dynamic exception) {
|
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
||||||
error = 'test failed unexpectedly: $exception';
|
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
||||||
});
|
])
|
||||||
expect(testLogger.statusText, '');
|
);
|
||||||
time.elapse(const Duration(milliseconds: 10000));
|
|
||||||
|
await net.fetchUrl(Uri.parse('http://example.invalid/'), maxAttempts: 4, durationOverride: Duration.zero);
|
||||||
|
|
||||||
expect(testLogger.statusText,
|
expect(testLogger.statusText,
|
||||||
'Download failed -- attempting retry 1 in 1 second...\n'
|
'Download failed -- attempting retry 1 in 1 second...\n'
|
||||||
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
||||||
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
||||||
'Download failed -- attempting retry 4 in 8 seconds...\n',
|
'Download failed -- retry 4\n',
|
||||||
);
|
);
|
||||||
});
|
|
||||||
expect(testLogger.errorText, isEmpty);
|
expect(testLogger.errorText, isEmpty);
|
||||||
expect(error, isNull);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('retry from SocketException', () async {
|
testWithoutContext('retry from SocketException', () async {
|
||||||
final Net net = createNet(FakeHttpClientThrowing(
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||||
const io.SocketException('test exception handling'),
|
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;
|
String error;
|
||||||
FakeAsync().run((FakeAsync time) {
|
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';
|
error = 'test completed unexpectedly';
|
||||||
}, onError: (dynamic exception) {
|
}, onError: (dynamic exception) {
|
||||||
error = 'test failed unexpectedly: $exception';
|
error = 'test failed unexpectedly: $exception';
|
||||||
@ -130,12 +149,18 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('no retry from HandshakeException', () async {
|
testWithoutContext('no retry from HandshakeException', () async {
|
||||||
final Net net = createNet(FakeHttpClientThrowing(
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||||
const io.HandshakeException('test exception handling'),
|
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;
|
String error;
|
||||||
FakeAsync().run((FakeAsync time) {
|
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';
|
error = 'test completed unexpectedly';
|
||||||
}, onError: (dynamic exception) {
|
}, onError: (dynamic exception) {
|
||||||
error = 'test failed: $exception';
|
error = 'test failed: $exception';
|
||||||
@ -149,10 +174,13 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('check for bad override on ArgumentError', () async {
|
testWithoutContext('check for bad override on ArgumentError', () async {
|
||||||
|
final Uri invalid = Uri.parse('example.invalid/');
|
||||||
final Net net = Net(
|
final Net net = Net(
|
||||||
httpClientFactory: () => FakeHttpClientThrowing(
|
httpClientFactory: () {
|
||||||
ArgumentError('test exception handling'),
|
return FakeHttpClient.list(<FakeRequest>[
|
||||||
),
|
FakeRequest(invalid, responseError: ArgumentError()),
|
||||||
|
]);
|
||||||
|
},
|
||||||
logger: testLogger,
|
logger: testLogger,
|
||||||
platform: FakePlatform(
|
platform: FakePlatform(
|
||||||
environment: <String, String>{
|
environment: <String, String>{
|
||||||
@ -177,12 +205,18 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('retry from HttpException', () async {
|
testWithoutContext('retry from HttpException', () async {
|
||||||
final Net net = createNet(FakeHttpClientThrowing(
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||||
const io.HttpException('test exception handling'),
|
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;
|
String error;
|
||||||
FakeAsync().run((FakeAsync time) {
|
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';
|
error = 'test completed unexpectedly';
|
||||||
}, onError: (dynamic exception) {
|
}, onError: (dynamic exception) {
|
||||||
error = 'test failed unexpectedly: $exception';
|
error = 'test failed unexpectedly: $exception';
|
||||||
@ -202,12 +236,18 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('retry from HttpException when request throws', () async {
|
testWithoutContext('retry from HttpException when request throws', () async {
|
||||||
final Net net = createNet(FakeHttpClientThrowingRequest(
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
||||||
const io.HttpException('test exception handling'),
|
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;
|
String error;
|
||||||
FakeAsync().run((FakeAsync time) {
|
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';
|
error = 'test completed unexpectedly';
|
||||||
}, onError: (dynamic exception) {
|
}, onError: (dynamic exception) {
|
||||||
error = 'test failed unexpectedly: $exception';
|
error = 'test failed unexpectedly: $exception';
|
||||||
@ -227,11 +267,24 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('max attempts', () async {
|
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;
|
String error;
|
||||||
List<int> actualResult;
|
List<int> actualResult;
|
||||||
FakeAsync().run((FakeAsync time) {
|
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;
|
actualResult = value;
|
||||||
}, onError: (dynamic exception) {
|
}, onError: (dynamic exception) {
|
||||||
error = 'test failed unexpectedly: $exception';
|
error = 'test failed unexpectedly: $exception';
|
||||||
@ -249,155 +302,40 @@ void main() {
|
|||||||
expect(actualResult, isNull);
|
expect(actualResult, isNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('remote file non-existant', () async {
|
testWithoutContext('remote file non-existent', () async {
|
||||||
final Net net = createNet(FakeHttpClient(404));
|
|
||||||
final Uri invalid = Uri.parse('http://example.invalid/');
|
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);
|
final bool result = await net.doesRemoteFileExist(invalid);
|
||||||
expect(result, false);
|
expect(result, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('remote file server error', () async {
|
testWithoutContext('remote file server error', () async {
|
||||||
final Net net = createNet(FakeHttpClient(500));
|
|
||||||
final Uri valid = Uri.parse('http://example.valid/');
|
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);
|
final bool result = await net.doesRemoteFileExist(valid);
|
||||||
expect(result, false);
|
expect(result, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('remote file exists', () async {
|
testWithoutContext('remote file exists', () async {
|
||||||
final Net net = createNet(FakeHttpClient(200));
|
|
||||||
final Uri valid = Uri.parse('http://example.valid/');
|
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);
|
final bool result = await net.doesRemoteFileExist(valid);
|
||||||
expect(result, true);
|
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/common.dart';
|
||||||
import '../src/context.dart';
|
import '../src/context.dart';
|
||||||
import '../src/testbed.dart';
|
import '../src/fake_http_client.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
BufferLogger logger;
|
BufferLogger logger;
|
||||||
@ -79,7 +79,7 @@ void main() {
|
|||||||
fileSystem: fs,
|
fileSystem: fs,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
flutterProjectFactory: FlutterProjectFactory(fileSystem: fs, logger: logger),
|
flutterProjectFactory: FlutterProjectFactory(fileSystem: fs, logger: logger),
|
||||||
client: FakeHttpClient(),
|
client: FakeHttpClient.any(),
|
||||||
);
|
);
|
||||||
|
|
||||||
final File file = fs.file('flutter_00.log');
|
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/common.dart';
|
||||||
import '../src/context.dart';
|
import '../src/context.dart';
|
||||||
|
import '../src/fake_http_client.dart';
|
||||||
|
|
||||||
final FakeVmServiceRequest createDevFSRequest = FakeVmServiceRequest(
|
final FakeVmServiceRequest createDevFSRequest = FakeVmServiceRequest(
|
||||||
method: '_createDevFS',
|
method: '_createDevFS',
|
||||||
@ -110,7 +111,6 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('DevFS create throws a DevFSException when vmservice disconnects unexpectedly', () async {
|
testWithoutContext('DevFS create throws a DevFSException when vmservice disconnects unexpectedly', () async {
|
||||||
final HttpClient httpClient = MockHttpClient();
|
|
||||||
final FileSystem fileSystem = MemoryFileSystem.test();
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
|
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
|
||||||
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||||
@ -118,16 +118,6 @@ void main() {
|
|||||||
);
|
);
|
||||||
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
|
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(
|
final DevFS devFS = DevFS(
|
||||||
fakeVmServiceHost.vmService,
|
fakeVmServiceHost.vmService,
|
||||||
'test',
|
'test',
|
||||||
@ -135,13 +125,12 @@ void main() {
|
|||||||
osUtils: osUtils,
|
osUtils: osUtils,
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
httpClient: httpClient,
|
httpClient: FakeHttpClient.any(),
|
||||||
);
|
);
|
||||||
expect(() async => await devFS.create(), throwsA(isA<DevFSException>()));
|
expect(() async => await devFS.create(), throwsA(isA<DevFSException>()));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('DevFS destroy is resiliant to vmservice disconnection', () async {
|
testWithoutContext('DevFS destroy is resilient to vmservice disconnection', () async {
|
||||||
final HttpClient httpClient = MockHttpClient();
|
|
||||||
final FileSystem fileSystem = MemoryFileSystem.test();
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
|
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
|
||||||
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||||
@ -152,15 +141,6 @@ void main() {
|
|||||||
);
|
);
|
||||||
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
|
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(
|
final DevFS devFS = DevFS(
|
||||||
fakeVmServiceHost.vmService,
|
fakeVmServiceHost.vmService,
|
||||||
@ -169,7 +149,7 @@ void main() {
|
|||||||
osUtils: osUtils,
|
osUtils: osUtils,
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
httpClient: httpClient,
|
httpClient: FakeHttpClient.any(),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(await devFS.create(), isNotNull);
|
expect(await devFS.create(), isNotNull);
|
||||||
@ -177,7 +157,6 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('DevFS retries uploads when connection reset by peer', () async {
|
testWithoutContext('DevFS retries uploads when connection reset by peer', () async {
|
||||||
final HttpClient httpClient = MockHttpClient();
|
|
||||||
final FileSystem fileSystem = MemoryFileSystem.test();
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
|
final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
|
||||||
final MockResidentCompiler residentCompiler = MockResidentCompiler();
|
final MockResidentCompiler residentCompiler = MockResidentCompiler();
|
||||||
@ -186,21 +165,6 @@ void main() {
|
|||||||
);
|
);
|
||||||
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
|
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(
|
when(residentCompiler.recompile(
|
||||||
any,
|
any,
|
||||||
any,
|
any,
|
||||||
@ -220,7 +184,14 @@ void main() {
|
|||||||
osUtils: osUtils,
|
osUtils: osUtils,
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: BufferLogger.test(),
|
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,
|
uploadRetryThrottle: Duration.zero,
|
||||||
);
|
);
|
||||||
await devFS.create();
|
await devFS.create();
|
||||||
@ -237,9 +208,7 @@ void main() {
|
|||||||
|
|
||||||
expect(report.syncedBytes, 5);
|
expect(report.syncedBytes, 5);
|
||||||
expect(report.success, isTrue);
|
expect(report.success, isTrue);
|
||||||
verify(httpClient.putUrl(any)).called(kFailedAttempts + 1);
|
verify(osUtils.gzipLevel1Stream(any)).called(6);
|
||||||
verify(httpRequest.close()).called(kFailedAttempts + 1);
|
|
||||||
verify(osUtils.gzipLevel1Stream(any)).called(kFailedAttempts + 1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('DevFS reports unsuccessful compile when errors are returned', () async {
|
testWithoutContext('DevFS reports unsuccessful compile when errors are returned', () async {
|
||||||
@ -255,7 +224,7 @@ void main() {
|
|||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
osUtils: FakeOperatingSystemUtils(),
|
osUtils: FakeOperatingSystemUtils(),
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
);
|
);
|
||||||
|
|
||||||
await devFS.create();
|
await devFS.create();
|
||||||
@ -290,16 +259,6 @@ void main() {
|
|||||||
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||||
requests: <VmServiceExpectation>[createDevFSRequest],
|
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(
|
final DevFS devFS = DevFS(
|
||||||
fakeVmServiceHost.vmService,
|
fakeVmServiceHost.vmService,
|
||||||
@ -308,7 +267,7 @@ void main() {
|
|||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
osUtils: FakeOperatingSystemUtils(),
|
osUtils: FakeOperatingSystemUtils(),
|
||||||
httpClient: httpClient,
|
httpClient: FakeHttpClient.any(),
|
||||||
);
|
);
|
||||||
|
|
||||||
await devFS.create();
|
await devFS.create();
|
||||||
@ -407,7 +366,7 @@ void main() {
|
|||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
osUtils: FakeOperatingSystemUtils(),
|
osUtils: FakeOperatingSystemUtils(),
|
||||||
httpClient: MockHttpClient(),
|
httpClient: FakeHttpClient.any(),
|
||||||
);
|
);
|
||||||
|
|
||||||
await devFS.create();
|
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 MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
|
||||||
class MockResidentCompiler extends Mock implements ResidentCompiler {}
|
class MockResidentCompiler extends Mock implements ResidentCompiler {}
|
||||||
class MockFile extends Mock implements File {}
|
class MockFile extends Mock implements File {}
|
||||||
|
@ -14,6 +14,7 @@ import 'package:flutter_tools/src/reporting/reporting.dart';
|
|||||||
|
|
||||||
import '../src/common.dart';
|
import '../src/common.dart';
|
||||||
import '../src/context.dart';
|
import '../src/context.dart';
|
||||||
|
import '../src/fake_http_client.dart';
|
||||||
import '../src/testbed.dart';
|
import '../src/testbed.dart';
|
||||||
|
|
||||||
const String _kShortURL = 'https://www.example.com/short';
|
const String _kShortURL = 'https://www.example.com/short';
|
||||||
@ -161,7 +162,14 @@ void main() {
|
|||||||
final GitHubTemplateCreator creator = GitHubTemplateCreator(
|
final GitHubTemplateCreator creator = GitHubTemplateCreator(
|
||||||
fileSystem: fs,
|
fileSystem: fs,
|
||||||
logger: logger,
|
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(
|
flutterProjectFactory: FlutterProjectFactory(
|
||||||
fileSystem: fs,
|
fileSystem: fs,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
@ -180,7 +188,11 @@ void main() {
|
|||||||
final GitHubTemplateCreator creator = GitHubTemplateCreator(
|
final GitHubTemplateCreator creator = GitHubTemplateCreator(
|
||||||
fileSystem: fs,
|
fileSystem: fs,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
client: FakeHttpClient(),
|
client: FakeHttpClient.list(<FakeRequest>[
|
||||||
|
FakeRequest(Uri.parse('https://git.io'), method: HttpMethod.post, response: const FakeResponse(
|
||||||
|
statusCode: 500,
|
||||||
|
))
|
||||||
|
]),
|
||||||
flutterProjectFactory: FlutterProjectFactory(
|
flutterProjectFactory: FlutterProjectFactory(
|
||||||
fileSystem: fs,
|
fileSystem: fs,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
@ -206,7 +218,7 @@ void main() {
|
|||||||
final GitHubTemplateCreator creator = GitHubTemplateCreator(
|
final GitHubTemplateCreator creator = GitHubTemplateCreator(
|
||||||
fileSystem: fs,
|
fileSystem: fs,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
client: FakeHttpClient(),
|
client: FakeHttpClient.any(),
|
||||||
flutterProjectFactory: FlutterProjectFactory(
|
flutterProjectFactory: FlutterProjectFactory(
|
||||||
fileSystem: fs,
|
fileSystem: fs,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
@ -292,37 +304,7 @@ device_info-0.4.1+4
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FakeError extends Error {
|
||||||
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 {
|
|
||||||
@override
|
@override
|
||||||
StackTrace get stackTrace => StackTrace.fromString('''
|
StackTrace get stackTrace => StackTrace.fromString('''
|
||||||
#0 _File.open.<anonymous closure> (dart:io/file_impl.dart:366:9)
|
#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 HttpClientRequest request = await client.getUrl(null);
|
||||||
final HttpClientResponse response = await request.close();
|
final HttpClientResponse response = await request.close();
|
||||||
|
|
||||||
expect(response.statusCode, HttpStatus.badRequest);
|
expect(response.statusCode, HttpStatus.ok);
|
||||||
expect(response.contentLength, 0);
|
expect(response.contentLength, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -37,6 +37,7 @@ import 'package:meta/meta.dart';
|
|||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
|
|
||||||
import 'common.dart';
|
import 'common.dart';
|
||||||
|
import 'fake_http_client.dart';
|
||||||
import 'fake_process_manager.dart';
|
import 'fake_process_manager.dart';
|
||||||
import 'fakes.dart';
|
import 'fakes.dart';
|
||||||
import 'throwing_pub.dart';
|
import 'throwing_pub.dart';
|
||||||
@ -112,7 +113,7 @@ void testUsingContext(
|
|||||||
DeviceManager: () => FakeDeviceManager(),
|
DeviceManager: () => FakeDeviceManager(),
|
||||||
Doctor: () => FakeDoctor(globals.logger),
|
Doctor: () => FakeDoctor(globals.logger),
|
||||||
FlutterVersion: () => MockFlutterVersion(),
|
FlutterVersion: () => MockFlutterVersion(),
|
||||||
HttpClient: () => MockHttpClient(),
|
HttpClient: () => FakeHttpClient.any(),
|
||||||
IOSSimulatorUtils: () {
|
IOSSimulatorUtils: () {
|
||||||
final MockIOSSimulatorUtils mock = MockIOSSimulatorUtils();
|
final MockIOSSimulatorUtils mock = MockIOSSimulatorUtils();
|
||||||
when(mock.getAttachedDevices()).thenAnswer((Invocation _) async => <IOSSimulator>[]);
|
when(mock.getAttachedDevices()).thenAnswer((Invocation _) async => <IOSSimulator>[]);
|
||||||
@ -378,8 +379,6 @@ class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter {
|
|||||||
|
|
||||||
class MockFlutterVersion extends Mock implements FlutterVersion {}
|
class MockFlutterVersion extends Mock implements FlutterVersion {}
|
||||||
|
|
||||||
class MockHttpClient extends Mock implements HttpClient {}
|
|
||||||
|
|
||||||
class MockCrashReporter extends Mock implements CrashReporter {}
|
class MockCrashReporter extends Mock implements CrashReporter {}
|
||||||
|
|
||||||
class LocalFileSystemBlockingSetCurrentDirectory extends LocalFileSystem {
|
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
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
@ -29,6 +28,7 @@ import 'package:process/process.dart';
|
|||||||
|
|
||||||
import 'common.dart' as tester;
|
import 'common.dart' as tester;
|
||||||
import 'context.dart';
|
import 'context.dart';
|
||||||
|
import 'fake_http_client.dart';
|
||||||
import 'throwing_pub.dart';
|
import 'throwing_pub.dart';
|
||||||
|
|
||||||
export 'package:flutter_tools/src/base/context.dart' show Generator;
|
export 'package:flutter_tools/src/base/context.dart' show Generator;
|
||||||
@ -154,7 +154,7 @@ class Testbed {
|
|||||||
return null;
|
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 }) {}
|
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 {
|
class FakeFlutterVersion implements FlutterVersion {
|
||||||
@override
|
@override
|
||||||
void fetchTagsAndUpdate() { }
|
void fetchTagsAndUpdate() { }
|
||||||
|
Loading…
Reference in New Issue
Block a user