blob: b379352615df07b9badd4abc9899e07f30231651 [file] [log] [blame]
// 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';
}
}