mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
b1a23299e1
* Added '--check-for-remote-artifacts' option for Flutter Doctor. This option takes a Flutter engine revision and issues HEAD requests to determine whether or not artifacts for the provided engine revision are available from cloud storage. This functionality is needed for the Dart SDK autoroller to avoid creating a PR to roll the engine into the framework while artifacts haven't finished building, which would cause Cirrus tests to fail.
207 lines
6.7 KiB
Dart
207 lines
6.7 KiB
Dart
// Copyright 2017 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:flutter_tools/src/base/io.dart' as io;
|
|
import 'package:flutter_tools/src/base/net.dart';
|
|
import 'package:quiver/testing/async.dart';
|
|
|
|
import '../src/common.dart';
|
|
import '../src/context.dart';
|
|
|
|
void main() {
|
|
testUsingContext('retry from 500', () async {
|
|
String error;
|
|
FakeAsync().run((FakeAsync time) {
|
|
fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
|
error = 'test completed unexpectedly';
|
|
}, onError: (dynamic exception) {
|
|
error = 'test failed unexpectedly: $exception';
|
|
});
|
|
expect(testLogger.statusText, '');
|
|
time.elapse(const Duration(milliseconds: 10000));
|
|
expect(testLogger.statusText,
|
|
'Download failed -- attempting retry 1 in 1 second...\n'
|
|
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
|
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
|
'Download failed -- attempting retry 4 in 8 seconds...\n'
|
|
);
|
|
});
|
|
expect(testLogger.errorText, isEmpty);
|
|
expect(error, isNull);
|
|
}, overrides: <Type, Generator>{
|
|
HttpClientFactory: () => () => MockHttpClient(500),
|
|
});
|
|
|
|
testUsingContext('retry from network error', () async {
|
|
String error;
|
|
FakeAsync().run((FakeAsync time) {
|
|
fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
|
error = 'test completed unexpectedly';
|
|
}, onError: (dynamic exception) {
|
|
error = 'test failed unexpectedly: $exception';
|
|
});
|
|
expect(testLogger.statusText, '');
|
|
time.elapse(const Duration(milliseconds: 10000));
|
|
expect(testLogger.statusText,
|
|
'Download failed -- attempting retry 1 in 1 second...\n'
|
|
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
|
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
|
'Download failed -- attempting retry 4 in 8 seconds...\n'
|
|
);
|
|
});
|
|
expect(testLogger.errorText, isEmpty);
|
|
expect(error, isNull);
|
|
}, overrides: <Type, Generator>{
|
|
HttpClientFactory: () => () => MockHttpClient(200),
|
|
});
|
|
|
|
testUsingContext('retry from SocketException', () async {
|
|
String error;
|
|
FakeAsync().run((FakeAsync time) {
|
|
fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
|
error = 'test completed unexpectedly';
|
|
}, onError: (dynamic exception) {
|
|
error = 'test failed unexpectedly: $exception';
|
|
});
|
|
expect(testLogger.statusText, '');
|
|
time.elapse(const Duration(milliseconds: 10000));
|
|
expect(testLogger.statusText,
|
|
'Download failed -- attempting retry 1 in 1 second...\n'
|
|
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
|
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
|
'Download failed -- attempting retry 4 in 8 seconds...\n'
|
|
);
|
|
});
|
|
expect(testLogger.errorText, isEmpty);
|
|
expect(error, isNull);
|
|
expect(testLogger.traceText, contains('Download error: SocketException'));
|
|
}, overrides: <Type, Generator>{
|
|
HttpClientFactory: () => () => MockHttpClientThrowing(
|
|
const io.SocketException('test exception handling'),
|
|
),
|
|
});
|
|
|
|
testUsingContext('no retry from HandshakeException', () async {
|
|
String error;
|
|
FakeAsync().run((FakeAsync time) {
|
|
fetchUrl(Uri.parse('http://example.invalid/')).then((List<int> value) {
|
|
error = 'test completed unexpectedly';
|
|
}, onError: (dynamic exception) {
|
|
error = 'test failed: $exception';
|
|
});
|
|
expect(testLogger.statusText, '');
|
|
time.elapse(const Duration(milliseconds: 10000));
|
|
expect(testLogger.statusText, '');
|
|
});
|
|
expect(error, startsWith('test failed'));
|
|
expect(testLogger.traceText, contains('HandshakeException'));
|
|
}, overrides: <Type, Generator>{
|
|
HttpClientFactory: () => () => MockHttpClientThrowing(
|
|
const io.HandshakeException('test exception handling'),
|
|
),
|
|
});
|
|
|
|
testUsingContext('remote file non-existant', () async {
|
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
|
final bool result = await doesRemoteFileExist(invalid);
|
|
expect(result, false);
|
|
}, overrides: <Type, Generator>{
|
|
HttpClientFactory: () => () => MockHttpClient(404),
|
|
});
|
|
|
|
testUsingContext('remote file server error', () async {
|
|
final Uri valid = Uri.parse('http://example.valid/');
|
|
final bool result = await doesRemoteFileExist(valid);
|
|
expect(result, false);
|
|
}, overrides: <Type, Generator>{
|
|
HttpClientFactory: () => () => MockHttpClient(500),
|
|
});
|
|
|
|
testUsingContext('remote file exists', () async {
|
|
final Uri valid = Uri.parse('http://example.valid/');
|
|
final bool result = await doesRemoteFileExist(valid);
|
|
expect(result, true);
|
|
}, overrides: <Type, Generator>{
|
|
HttpClientFactory: () => () => MockHttpClient(200),
|
|
});
|
|
}
|
|
|
|
class MockHttpClientThrowing implements io.HttpClient {
|
|
MockHttpClientThrowing(this.exception);
|
|
|
|
final Exception exception;
|
|
|
|
@override
|
|
Future<io.HttpClientRequest> getUrl(Uri url) async {
|
|
throw exception;
|
|
}
|
|
|
|
@override
|
|
dynamic noSuchMethod(Invocation invocation) {
|
|
throw 'io.HttpClient - $invocation';
|
|
}
|
|
}
|
|
|
|
class MockHttpClient implements io.HttpClient {
|
|
MockHttpClient(this.statusCode);
|
|
|
|
final int statusCode;
|
|
|
|
@override
|
|
Future<io.HttpClientRequest> getUrl(Uri url) async {
|
|
return MockHttpClientRequest(statusCode);
|
|
}
|
|
|
|
@override
|
|
Future<io.HttpClientRequest> headUrl(Uri url) async {
|
|
return MockHttpClientRequest(statusCode);
|
|
}
|
|
|
|
@override
|
|
dynamic noSuchMethod(Invocation invocation) {
|
|
throw 'io.HttpClient - $invocation';
|
|
}
|
|
}
|
|
|
|
class MockHttpClientRequest implements io.HttpClientRequest {
|
|
MockHttpClientRequest(this.statusCode);
|
|
|
|
final int statusCode;
|
|
|
|
@override
|
|
Future<io.HttpClientResponse> close() async {
|
|
return MockHttpClientResponse(statusCode);
|
|
}
|
|
|
|
@override
|
|
dynamic noSuchMethod(Invocation invocation) {
|
|
throw 'io.HttpClientRequest - $invocation';
|
|
}
|
|
}
|
|
|
|
class MockHttpClientResponse extends Stream<List<int>> implements io.HttpClientResponse {
|
|
MockHttpClientResponse(this.statusCode);
|
|
|
|
@override
|
|
final int statusCode;
|
|
|
|
@override
|
|
String get reasonPhrase => '<reason phrase>';
|
|
|
|
@override
|
|
StreamSubscription<List<int>> listen(void onData(List<int> event), {
|
|
Function onError, void onDone(), bool cancelOnError
|
|
}) {
|
|
return Stream<List<int>>.fromFuture(Future<List<int>>.error(const io.SocketException('test')))
|
|
.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
|
}
|
|
|
|
@override
|
|
dynamic noSuchMethod(Invocation invocation) {
|
|
throw 'io.HttpClientResponse - $invocation';
|
|
}
|
|
}
|