[flutter_tools] remove package HTTP and add pub.dev head check tests (#75871)

This commit is contained in:
Jonah Williams 2021-02-12 10:44:19 -08:00 committed by GitHub
parent af0ea8c3db
commit 980880e2b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 125 additions and 31 deletions

View file

@ -6,7 +6,6 @@
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';
import 'package:process/process.dart';
@ -19,8 +18,8 @@ import 'resident_runner.dart';
/// An implementation of the devtools launcher that uses the server package.
///
/// This is implemented in isolated to prevent the flutter_tool from needing
/// a devtools dep in google3.
/// This is implemented in `isolated/` to prevent the flutter_tool from needing
/// a devtools dependency in google3.
class DevtoolsServerLauncher extends DevtoolsLauncher {
DevtoolsServerLauncher({
@required Platform platform,
@ -28,22 +27,26 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
@required String pubExecutable,
@required Logger logger,
@required PersistentToolState persistentToolState,
@visibleForTesting io.HttpClient httpClient,
}) : _processManager = processManager,
_pubExecutable = pubExecutable,
_logger = logger,
_platform = platform,
_persistentToolState = persistentToolState;
_persistentToolState = persistentToolState,
_httpClient = httpClient ?? io.HttpClient();
final ProcessManager _processManager;
final String _pubExecutable;
final Logger _logger;
final Platform _platform;
final PersistentToolState _persistentToolState;
final io.HttpClient _httpClient;
io.Process _devToolsProcess;
static final RegExp _serveDevToolsPattern =
RegExp(r'Serving DevTools at ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+)');
static const String _pubHostedUrlKey = 'PUB_HOSTED_URL';
@override
Future<void> launch(Uri vmServiceUri) async {
@ -51,15 +54,33 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
// this method is guaranteed not to return a Future that throws.
try {
bool offline = false;
bool useOverrideUrl = false;
try {
const String pubHostedUrlKey = 'PUB_HOSTED_URL';
if (_platform.environment.containsKey(pubHostedUrlKey)) {
await http.head(Uri.parse(_platform.environment[pubHostedUrlKey]));
Uri uri;
if (_platform.environment.containsKey(_pubHostedUrlKey)) {
useOverrideUrl = true;
uri = Uri.parse(_platform.environment[_pubHostedUrlKey]);
} else {
await http.head(Uri.https('pub.dev', ''));
uri = Uri.https('pub.dev', '');
}
final io.HttpClientRequest request = await _httpClient.headUrl(uri);
final io.HttpClientResponse response = await request.close();
await response.drain<void>();
if (response.statusCode != io.HttpStatus.ok) {
offline = true;
}
} on Exception {
offline = true;
} on ArgumentError {
if (!useOverrideUrl) {
rethrow;
}
// The user supplied a custom pub URL that was invalid, pretend to be offline
// and inform them that the URL was invalid.
offline = true;
_logger.printError(
'PUB_HOSTED_URL was set to an invalid URL: "${_platform.environment[_pubHostedUrlKey]}".'
);
}
if (offline) {

View file

@ -40,7 +40,7 @@ void main() {
await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
);
expect(logger.statusText, contains('test message'));
@ -67,7 +67,7 @@ void main() {
await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
);
expect(logger.statusText, contains('test message'));
@ -88,7 +88,7 @@ void main() {
operatingSystemUtils: operatingSystemUtils,
platform: testPlatform,
httpClient: FakeHttpClient.list(<FakeRequest>[
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(
FakeRequest(Uri.parse('http://test.zip'), response: const FakeResponse(
headers: <String, List<String>>{
'x-goog-hash': <String>[],
}
@ -100,7 +100,7 @@ void main() {
await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
);
expect(logger.statusText, contains('test message'));
@ -119,7 +119,7 @@ void main() {
operatingSystemUtils: operatingSystemUtils,
platform: testPlatform,
httpClient: FakeHttpClient.list(<FakeRequest>[
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(
FakeRequest(Uri.parse('http://test.zip'), response: const FakeResponse(
body: <int>[0],
headers: <String, List<String>>{
'x-goog-hash': <String>[
@ -135,7 +135,7 @@ void main() {
await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
);
expect(logger.statusText, contains('test message'));
@ -154,7 +154,7 @@ void main() {
operatingSystemUtils: operatingSystemUtils,
platform: testPlatform,
httpClient: FakeHttpClient.list(<FakeRequest>[
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(
FakeRequest(Uri.parse('http://test.zip'), response: const FakeResponse(
body: <int>[0],
headers: <String, List<String>>{
'x-goog-hash': <String>[
@ -163,7 +163,7 @@ void main() {
],
}
)),
FakeRequest(Uri.parse('http:///test.zip'), response: const FakeResponse(
FakeRequest(Uri.parse('http://test.zip'), response: const FakeResponse(
headers: <String, List<String>>{
'x-goog-hash': <String>[
'foo-bar-baz',
@ -178,7 +178,7 @@ void main() {
await expectLater(() async => await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
), throwsToolExit(message: 'k7iFrf4SQT9WfcQ==')); // validate that the hash mismatch message is included.
});
@ -197,8 +197,8 @@ void main() {
operatingSystemUtils: operatingSystemUtils,
platform: testPlatform,
httpClient: FakeHttpClient.list(<FakeRequest>[
FakeRequest(Uri.parse('http:///test.zip'), responseError: const HttpException('')),
FakeRequest(Uri.parse('http:///test.zip')),
FakeRequest(Uri.parse('http://test.zip'), responseError: const HttpException('')),
FakeRequest(Uri.parse('http://test.zip')),
]),
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
..createSync(),
@ -206,7 +206,7 @@ void main() {
await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
);
@ -224,8 +224,8 @@ void main() {
operatingSystemUtils: operatingSystemUtils,
platform: testPlatform,
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)),
FakeRequest(Uri.parse('http://test.zip'), response: const FakeResponse(statusCode: HttpStatus.preconditionFailed)),
FakeRequest(Uri.parse('http://test.zip'), response: const FakeResponse(statusCode: HttpStatus.preconditionFailed)),
]),
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
..createSync(),
@ -233,7 +233,7 @@ void main() {
await expectLater(() async => await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
), throwsToolExit());
@ -281,7 +281,7 @@ void main() {
operatingSystemUtils: operatingSystemUtils,
platform: testPlatform,
httpClient: FakeHttpClient.list(<FakeRequest>[
FakeRequest(Uri.parse('http:///test.zip'), responseError: ArgumentError()),
FakeRequest(Uri.parse('http://test.zip'), responseError: ArgumentError()),
]),
tempStorage: fileSystem.currentDirectory.childDirectory('temp')
..createSync(),
@ -289,7 +289,7 @@ void main() {
await expectLater(() async => await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
), throwsA(isA<ArgumentError>()));
@ -314,7 +314,7 @@ void main() {
await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
);
expect(logger.statusText, contains('test message'));
@ -338,7 +338,7 @@ void main() {
await artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
);
expect(logger.statusText, contains('test message'));
@ -362,7 +362,7 @@ void main() {
expect(artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
), throwsA(isA<ToolExit>()));
expect(fileSystem.file('te,[/test'), isNot(exists));
@ -386,7 +386,7 @@ void main() {
expect(artifactUpdater.downloadZipArchive(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
), throwsA(isA<ToolExit>()));
expect(fileSystem.file('te,[/test'), isNot(exists));
@ -409,7 +409,7 @@ void main() {
await artifactUpdater.downloadZippedTarball(
'test message',
Uri.parse('http:///test.zip'),
Uri.parse('http://test.zip'),
fileSystem.currentDirectory.childDirectory('out'),
);
expect(fileSystem.file('out/test'), exists);

View file

@ -259,6 +259,7 @@ void main() {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[createDevFSRequest],
);
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
final DevFS devFS = DevFS(
fakeVmServiceHost.vmService,

View file

@ -17,6 +17,7 @@ import 'package:flutter_tools/src/resident_runner.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/fake_http_client.dart';
void main() {
BufferLogger logger;
@ -34,6 +35,65 @@ void main() {
);
});
testWithoutContext('DevtoolsLauncher does not launch devtools if unable to reach pub.dev', () async {
final DevtoolsLauncher launcher = DevtoolsServerLauncher(
pubExecutable: 'pub',
logger: logger,
platform: platform,
persistentToolState: persistentToolState,
httpClient: FakeHttpClient.list(<FakeRequest>[
FakeRequest(
Uri.https('pub.dev', ''),
method: HttpMethod.head,
response: const FakeResponse(statusCode: HttpStatus.internalServerError),
),
]),
processManager: FakeProcessManager.list(<FakeCommand>[]),
);
final DevToolsServerAddress address = await launcher.serve();
expect(address, isNull);
});
testWithoutContext('DevtoolsLauncher pings PUB_HOSTED_URL instead of pub.dev for online check', () async {
final DevtoolsLauncher launcher = DevtoolsServerLauncher(
pubExecutable: 'pub',
logger: logger,
platform: FakePlatform(environment: <String, String>{
'PUB_HOSTED_URL': 'https://pub2.dev'
}),
persistentToolState: persistentToolState,
httpClient: FakeHttpClient.list(<FakeRequest>[
FakeRequest(
Uri.https('pub2.dev', ''),
method: HttpMethod.head,
response: const FakeResponse(statusCode: HttpStatus.internalServerError),
),
]),
processManager: FakeProcessManager.list(<FakeCommand>[]),
);
final DevToolsServerAddress address = await launcher.serve();
expect(address, isNull);
});
testWithoutContext('DevtoolsLauncher handles an invalid PUB_HOSTED_URL', () async {
final DevtoolsLauncher launcher = DevtoolsServerLauncher(
pubExecutable: 'pub',
logger: logger,
platform: FakePlatform(environment: <String, String>{
'PUB_HOSTED_URL': r'not_an_http_url'
}),
persistentToolState: persistentToolState,
httpClient: FakeHttpClient.list(<FakeRequest>[]),
processManager: FakeProcessManager.list(<FakeCommand>[]),
);
final DevToolsServerAddress address = await launcher.serve();
expect(address, isNull);
expect(logger.errorText, contains('PUB_HOSTED_URL was set to an invalid URL: "not_an_http_url".'));
});
testWithoutContext('DevtoolsLauncher launches DevTools through pub and saves the URI', () async {
final Completer<void> completer = Completer<void>();
final DevtoolsLauncher launcher = DevtoolsServerLauncher(
@ -41,6 +101,7 @@ void main() {
logger: logger,
platform: platform,
persistentToolState: persistentToolState,
httpClient: FakeHttpClient.any(),
processManager: FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>[
@ -85,6 +146,7 @@ void main() {
logger: logger,
platform: platform,
persistentToolState: persistentToolState,
httpClient: FakeHttpClient.any(),
processManager: FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>[
@ -129,6 +191,7 @@ void main() {
logger: logger,
platform: platform,
persistentToolState: persistentToolState,
httpClient: FakeHttpClient.any(),
processManager: FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>[
@ -178,6 +241,7 @@ void main() {
logger: logger,
platform: platform,
persistentToolState: persistentToolState,
httpClient: FakeHttpClient.any(),
processManager: FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>[
@ -209,6 +273,7 @@ void main() {
logger: logger,
platform: platform,
persistentToolState: persistentToolState,
httpClient: FakeHttpClient.any(),
processManager: FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>[
@ -253,6 +318,7 @@ void main() {
logger: logger,
platform: platform,
persistentToolState: persistentToolState,
httpClient: FakeHttpClient.any(),
processManager: FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>[

View file

@ -66,7 +66,7 @@ void main() {
final Testbed testbed = Testbed();
await testbed.run(() async {
final HttpClient client = HttpClient();
final HttpClientRequest request = await client.getUrl(null);
final HttpClientRequest request = await client.getUrl(Uri.parse('http://foo.dev'));
final HttpClientResponse response = await request.close();
expect(response.statusCode, HttpStatus.ok);

View file

@ -263,6 +263,12 @@ class FakeHttpClient implements HttpClient {
int _requestCount = 0;
_FakeHttpClientRequest _findRequest(HttpMethod method, Uri uri) {
// Ensure the fake client throws similar errors to the real client.
if (uri.host.isEmpty) {
throw ArgumentError('No host specified in URI $uri');
} else if (uri.scheme != 'http' && uri.scheme != 'https') {
throw ArgumentError("Unsupported scheme '${uri.scheme}' in URI $uri");
}
final String methodString = _toMethodString(method);
if (_any) {
return _FakeHttpClientRequest(