mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

This auto-formats all *.dart files in the repository outside of the `engine` subdirectory and enforces that these files stay formatted with a presubmit check. **Reviewers:** Please carefully review all the commits except for the one titled "formatted". The "formatted" commit was auto-generated by running `dev/tools/format.sh -a -f`. The other commits were hand-crafted to prepare the repo for the formatting change. I recommend reviewing the commits one-by-one via the "Commits" tab and avoiding Github's "Files changed" tab as it will likely slow down your browser because of the size of this PR. --------- Co-authored-by: Kate Lovett <katelovett@google.com> Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
397 lines
14 KiB
Dart
397 lines
14 KiB
Dart
// 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.
|
|
|
|
import 'dart:convert';
|
|
|
|
import 'package:fake_async/fake_async.dart';
|
|
import 'package:file/file.dart';
|
|
import 'package:file/memory.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/base/io.dart' as io;
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/base/net.dart';
|
|
import 'package:flutter_tools/src/base/platform.dart';
|
|
|
|
import '../../src/common.dart';
|
|
import '../../src/fake_http_client.dart';
|
|
|
|
void main() {
|
|
late BufferLogger testLogger;
|
|
|
|
setUp(() {
|
|
testLogger = BufferLogger.test();
|
|
});
|
|
|
|
Net createNet(io.HttpClient client) {
|
|
return Net(httpClientFactory: () => client, logger: testLogger, platform: FakePlatform());
|
|
}
|
|
|
|
group('successful fetch', () {
|
|
const String responseString = 'response string';
|
|
late List<int> responseData;
|
|
|
|
setUp(() {
|
|
responseData = utf8.encode(responseString);
|
|
});
|
|
|
|
testWithoutContext('fetchUrl() gets the data', () async {
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(
|
|
Uri.parse('http://example.invalid/'),
|
|
response: FakeResponse(body: utf8.encode(responseString)),
|
|
),
|
|
]),
|
|
);
|
|
|
|
final List<int>? data = await net.fetchUrl(Uri.parse('http://example.invalid/'));
|
|
expect(data, equals(responseData));
|
|
});
|
|
|
|
testWithoutContext('fetchUrl(destFile) writes the data to a file', () async {
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(
|
|
Uri.parse('http://example.invalid/'),
|
|
response: FakeResponse(body: utf8.encode(responseString)),
|
|
),
|
|
]),
|
|
);
|
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
|
final File destFile = fileSystem.file('dest_file')..createSync();
|
|
final List<int>? data = await net.fetchUrl(
|
|
Uri.parse('http://example.invalid/'),
|
|
destFile: destFile,
|
|
);
|
|
expect(data, equals(<int>[]));
|
|
expect(destFile.readAsStringSync(), responseString);
|
|
});
|
|
});
|
|
|
|
testWithoutContext('retry from 500', () async {
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(
|
|
Uri.parse('http://example.invalid/'),
|
|
response: const FakeResponse(statusCode: io.HttpStatus.internalServerError),
|
|
),
|
|
FakeRequest(
|
|
Uri.parse('http://example.invalid/'),
|
|
response: const FakeResponse(statusCode: io.HttpStatus.internalServerError),
|
|
),
|
|
FakeRequest(
|
|
Uri.parse('http://example.invalid/'),
|
|
response: const FakeResponse(statusCode: io.HttpStatus.internalServerError),
|
|
),
|
|
FakeRequest(
|
|
Uri.parse('http://example.invalid/'),
|
|
response: const FakeResponse(statusCode: io.HttpStatus.internalServerError),
|
|
),
|
|
]),
|
|
);
|
|
|
|
await net.fetchUrl(
|
|
Uri.parse('http://example.invalid/'),
|
|
maxAttempts: 4,
|
|
durationOverride: Duration.zero,
|
|
);
|
|
|
|
expect(
|
|
testLogger.statusText,
|
|
'Download failed -- attempting retry 1 in 1 second...\n'
|
|
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
|
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
|
'Download failed -- retry 4\n',
|
|
);
|
|
expect(testLogger.errorText, isEmpty);
|
|
});
|
|
|
|
testWithoutContext('retry from network error', () async {
|
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
|
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
|
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
|
FakeRequest(invalid, responseError: const io.SocketException('test')),
|
|
]),
|
|
);
|
|
|
|
await net.fetchUrl(
|
|
Uri.parse('http://example.invalid/'),
|
|
maxAttempts: 4,
|
|
durationOverride: Duration.zero,
|
|
);
|
|
|
|
expect(
|
|
testLogger.statusText,
|
|
'Download failed -- attempting retry 1 in 1 second...\n'
|
|
'Download failed -- attempting retry 2 in 2 seconds...\n'
|
|
'Download failed -- attempting retry 3 in 4 seconds...\n'
|
|
'Download failed -- retry 4\n',
|
|
);
|
|
expect(testLogger.errorText, isEmpty);
|
|
});
|
|
|
|
testWithoutContext('retry from SocketException', () async {
|
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(invalid, responseError: const io.SocketException('')),
|
|
FakeRequest(invalid, responseError: const io.SocketException('')),
|
|
FakeRequest(invalid, responseError: const io.SocketException('')),
|
|
FakeRequest(invalid, responseError: const io.SocketException('')),
|
|
]),
|
|
);
|
|
String? error;
|
|
FakeAsync().run((FakeAsync time) {
|
|
net
|
|
.fetchUrl(invalid)
|
|
.then(
|
|
(List<int>? value) async {
|
|
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'));
|
|
});
|
|
|
|
testWithoutContext('no retry from HandshakeException', () async {
|
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(invalid, responseError: const io.HandshakeException()),
|
|
FakeRequest(invalid, responseError: const io.HandshakeException()),
|
|
FakeRequest(invalid, responseError: const io.HandshakeException()),
|
|
FakeRequest(invalid, responseError: const io.HandshakeException()),
|
|
]),
|
|
);
|
|
String? error;
|
|
FakeAsync().run((FakeAsync time) {
|
|
net
|
|
.fetchUrl(invalid)
|
|
.then(
|
|
(List<int>? value) async {
|
|
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'));
|
|
});
|
|
|
|
testWithoutContext('check for bad override on ArgumentError', () async {
|
|
final Uri invalid = Uri.parse('example.invalid/');
|
|
final Net net = Net(
|
|
httpClientFactory: () {
|
|
return FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(invalid, responseError: ArgumentError()),
|
|
]);
|
|
},
|
|
logger: testLogger,
|
|
platform: FakePlatform(
|
|
environment: <String, String>{'FLUTTER_STORAGE_BASE_URL': 'example.invalid'},
|
|
),
|
|
);
|
|
String? error;
|
|
FakeAsync().run((FakeAsync time) {
|
|
net
|
|
.fetchUrl(Uri.parse('example.invalid/'))
|
|
.then(
|
|
(List<int>? value) async {
|
|
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.errorText, contains('Invalid argument'));
|
|
expect(error, contains('FLUTTER_STORAGE_BASE_URL'));
|
|
});
|
|
|
|
testWithoutContext('retry from HttpException', () async {
|
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(invalid, responseError: const io.HttpException('')),
|
|
FakeRequest(invalid, responseError: const io.HttpException('')),
|
|
FakeRequest(invalid, responseError: const io.HttpException('')),
|
|
FakeRequest(invalid, responseError: const io.HttpException('')),
|
|
]),
|
|
);
|
|
String? error;
|
|
FakeAsync().run((FakeAsync time) {
|
|
net
|
|
.fetchUrl(invalid)
|
|
.then(
|
|
(List<int>? value) async {
|
|
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: HttpException'));
|
|
});
|
|
|
|
testWithoutContext('retry from HttpException when request throws', () async {
|
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(invalid, responseError: const io.HttpException('')),
|
|
FakeRequest(invalid, responseError: const io.HttpException('')),
|
|
FakeRequest(invalid, responseError: const io.HttpException('')),
|
|
FakeRequest(invalid, responseError: const io.HttpException('')),
|
|
]),
|
|
);
|
|
String? error;
|
|
FakeAsync().run((FakeAsync time) {
|
|
net
|
|
.fetchUrl(invalid)
|
|
.then(
|
|
(List<int>? value) async {
|
|
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: HttpException'));
|
|
});
|
|
|
|
testWithoutContext('max attempts', () async {
|
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(
|
|
invalid,
|
|
response: const FakeResponse(statusCode: HttpStatus.internalServerError),
|
|
),
|
|
FakeRequest(
|
|
invalid,
|
|
response: const FakeResponse(statusCode: HttpStatus.internalServerError),
|
|
),
|
|
FakeRequest(
|
|
invalid,
|
|
response: const FakeResponse(statusCode: HttpStatus.internalServerError),
|
|
),
|
|
]),
|
|
);
|
|
String? error;
|
|
List<int>? actualResult;
|
|
FakeAsync().run((FakeAsync time) {
|
|
net
|
|
.fetchUrl(invalid, maxAttempts: 3)
|
|
.then(
|
|
(List<int>? value) async {
|
|
actualResult = value;
|
|
},
|
|
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 -- retry 3\n',
|
|
);
|
|
});
|
|
expect(testLogger.errorText, isEmpty);
|
|
expect(error, isNull);
|
|
expect(actualResult, isNull);
|
|
});
|
|
|
|
testWithoutContext('remote file non-existent', () async {
|
|
final Uri invalid = Uri.parse('http://example.invalid/');
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(
|
|
invalid,
|
|
method: HttpMethod.head,
|
|
response: const FakeResponse(statusCode: HttpStatus.notFound),
|
|
),
|
|
]),
|
|
);
|
|
final bool result = await net.doesRemoteFileExist(invalid);
|
|
expect(result, false);
|
|
});
|
|
|
|
testWithoutContext('remote file server error', () async {
|
|
final Uri valid = Uri.parse('http://example.valid/');
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[
|
|
FakeRequest(
|
|
valid,
|
|
method: HttpMethod.head,
|
|
response: const FakeResponse(statusCode: HttpStatus.internalServerError),
|
|
),
|
|
]),
|
|
);
|
|
final bool result = await net.doesRemoteFileExist(valid);
|
|
expect(result, false);
|
|
});
|
|
|
|
testWithoutContext('remote file exists', () async {
|
|
final Uri valid = Uri.parse('http://example.valid/');
|
|
final Net net = createNet(
|
|
FakeHttpClient.list(<FakeRequest>[FakeRequest(valid, method: HttpMethod.head)]),
|
|
);
|
|
final bool result = await net.doesRemoteFileExist(valid);
|
|
expect(result, true);
|
|
});
|
|
}
|