Reland: [flutter_tools] Disable analytics for more bots (#50641)
This commit is contained in:
parent
3aa72cc2f2
commit
b9ecebf101
@ -9,7 +9,6 @@ import 'package:intl/intl.dart' as intl;
|
||||
import 'package:intl/intl_standalone.dart' as intl_standalone;
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'src/base/bot_detector.dart';
|
||||
import 'src/base/common.dart';
|
||||
import 'src/base/context.dart';
|
||||
import 'src/base/file_system.dart';
|
||||
@ -35,8 +34,8 @@ Future<int> run(
|
||||
bool reportCrashes,
|
||||
String flutterVersion,
|
||||
Map<Type, Generator> overrides,
|
||||
}) {
|
||||
reportCrashes ??= !isRunningOnBot(globals.platform);
|
||||
}) async {
|
||||
reportCrashes ??= !await globals.isRunningOnBot;
|
||||
|
||||
if (muteCommandLogging) {
|
||||
// Remove the verbose option; for help and doctor, users don't need to see
|
||||
|
@ -5,56 +5,107 @@
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
import 'context.dart';
|
||||
import 'io.dart';
|
||||
import 'net.dart';
|
||||
|
||||
class BotDetector {
|
||||
BotDetector({
|
||||
@required HttpClientFactory httpClientFactory,
|
||||
@required Platform platform,
|
||||
}) : _platform = platform;
|
||||
}) :
|
||||
_platform = platform,
|
||||
_azureDetector = AzureDetector(
|
||||
httpClientFactory: httpClientFactory,
|
||||
);
|
||||
|
||||
final Platform _platform;
|
||||
final AzureDetector _azureDetector;
|
||||
|
||||
bool get isRunningOnBot {
|
||||
bool _isRunningOnBot;
|
||||
|
||||
Future<bool> get isRunningOnBot async {
|
||||
if (_isRunningOnBot != null) {
|
||||
return _isRunningOnBot;
|
||||
}
|
||||
if (
|
||||
// Explicitly stated to not be a bot.
|
||||
_platform.environment['BOT'] == 'false'
|
||||
// Explicitly stated to not be a bot.
|
||||
_platform.environment['BOT'] == 'false'
|
||||
|
||||
// Set by the IDEs to the IDE name, so a strong signal that this is not a bot.
|
||||
|| _platform.environment.containsKey('FLUTTER_HOST')
|
||||
// When set, GA logs to a local file (normally for tests) so we don't need to filter.
|
||||
|| _platform.environment.containsKey('FLUTTER_ANALYTICS_LOG_FILE')
|
||||
// Set by the IDEs to the IDE name, so a strong signal that this is not a bot.
|
||||
|| _platform.environment.containsKey('FLUTTER_HOST')
|
||||
// When set, GA logs to a local file (normally for tests) so we don't need to filter.
|
||||
|| _platform.environment.containsKey('FLUTTER_ANALYTICS_LOG_FILE')
|
||||
) {
|
||||
return false;
|
||||
return _isRunningOnBot = false;
|
||||
}
|
||||
|
||||
return _platform.environment['BOT'] == 'true'
|
||||
return _isRunningOnBot = _platform.environment['BOT'] == 'true'
|
||||
|
||||
// https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
|
||||
|| _platform.environment['TRAVIS'] == 'true'
|
||||
|| _platform.environment['CONTINUOUS_INTEGRATION'] == 'true'
|
||||
|| _platform.environment.containsKey('CI') // Travis and AppVeyor
|
||||
// https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
|
||||
|| _platform.environment['TRAVIS'] == 'true'
|
||||
|| _platform.environment['CONTINUOUS_INTEGRATION'] == 'true'
|
||||
|| _platform.environment.containsKey('CI') // Travis and AppVeyor
|
||||
|
||||
// https://www.appveyor.com/docs/environment-variables/
|
||||
|| _platform.environment.containsKey('APPVEYOR')
|
||||
// https://www.appveyor.com/docs/environment-variables/
|
||||
|| _platform.environment.containsKey('APPVEYOR')
|
||||
|
||||
// https://cirrus-ci.org/guide/writing-tasks/#environment-variables
|
||||
|| _platform.environment.containsKey('CIRRUS_CI')
|
||||
// https://cirrus-ci.org/guide/writing-tasks/#environment-variables
|
||||
|| _platform.environment.containsKey('CIRRUS_CI')
|
||||
|
||||
// https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
|
||||
|| (_platform.environment.containsKey('AWS_REGION') &&
|
||||
_platform.environment.containsKey('CODEBUILD_INITIATOR'))
|
||||
// https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
|
||||
|| (_platform.environment.containsKey('AWS_REGION') &&
|
||||
_platform.environment.containsKey('CODEBUILD_INITIATOR'))
|
||||
|
||||
// https://wiki.jenkins.io/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-belowJenkinsSetEnvironmentVariables
|
||||
|| _platform.environment.containsKey('JENKINS_URL')
|
||||
// https://wiki.jenkins.io/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-belowJenkinsSetEnvironmentVariables
|
||||
|| _platform.environment.containsKey('JENKINS_URL')
|
||||
|
||||
// Properties on Flutter's Chrome Infra bots.
|
||||
|| _platform.environment['CHROME_HEADLESS'] == '1'
|
||||
|| _platform.environment.containsKey('BUILDBOT_BUILDERNAME')
|
||||
|| _platform.environment.containsKey('SWARMING_TASK_ID');
|
||||
// https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables
|
||||
|| _platform.environment.containsKey('GITHUB_ACTIONS')
|
||||
|
||||
// Properties on Flutter's Chrome Infra bots.
|
||||
|| _platform.environment['CHROME_HEADLESS'] == '1'
|
||||
|| _platform.environment.containsKey('BUILDBOT_BUILDERNAME')
|
||||
|| _platform.environment.containsKey('SWARMING_TASK_ID')
|
||||
|| await _azureDetector.isRunningOnAzure;
|
||||
}
|
||||
}
|
||||
|
||||
bool isRunningOnBot(Platform platform) {
|
||||
final BotDetector botDetector = context.get<BotDetector>() ?? BotDetector(platform: platform);
|
||||
return botDetector.isRunningOnBot;
|
||||
// Are we running on Azure?
|
||||
// https://docs.microsoft.com/en-us/azure/virtual-machines/linux/instance-metadata-service
|
||||
@visibleForTesting
|
||||
class AzureDetector {
|
||||
AzureDetector({
|
||||
@required HttpClientFactory httpClientFactory,
|
||||
}) : _httpClientFactory = httpClientFactory;
|
||||
|
||||
static const String _serviceUrl = 'http://169.254.169.254/metadata/instance';
|
||||
|
||||
final HttpClientFactory _httpClientFactory;
|
||||
|
||||
bool _isRunningOnAzure;
|
||||
|
||||
Future<bool> get isRunningOnAzure async {
|
||||
if (_isRunningOnAzure != null) {
|
||||
return _isRunningOnAzure;
|
||||
}
|
||||
final HttpClient client = _httpClientFactory()
|
||||
..connectionTimeout = const Duration(seconds: 1);
|
||||
try {
|
||||
final HttpClientRequest request = await client.getUrl(
|
||||
Uri.parse(_serviceUrl),
|
||||
);
|
||||
request.headers.add('Metadata', true);
|
||||
await request.close();
|
||||
} on SocketException {
|
||||
// If there is an error on the socket, it probalby means that we are not
|
||||
// running on Azure.
|
||||
return _isRunningOnAzure = false;
|
||||
} on HttpException {
|
||||
// If the connection gets set up, but encounters an error condition, it
|
||||
// still means we're on Azure.
|
||||
return _isRunningOnAzure = true;
|
||||
}
|
||||
// We got a response. We're running on Azure.
|
||||
return _isRunningOnAzure = true;
|
||||
}
|
||||
}
|
||||
|
@ -61,9 +61,18 @@ Future<T> runInContext<T>(
|
||||
FutureOr<T> runner(), {
|
||||
Map<Type, Generator> overrides,
|
||||
}) async {
|
||||
|
||||
// Wrap runner with any asynchronous initialization that should run with the
|
||||
// overrides and callbacks.
|
||||
bool runningOnBot;
|
||||
FutureOr<T> runnerWrapper() async {
|
||||
runningOnBot = await globals.isRunningOnBot;
|
||||
return runner();
|
||||
}
|
||||
|
||||
return await context.run<T>(
|
||||
name: 'global fallbacks',
|
||||
body: runner,
|
||||
body: runnerWrapper,
|
||||
overrides: overrides,
|
||||
fallbacks: <Type, Generator>{
|
||||
AndroidLicenseValidator: () => AndroidLicenseValidator(),
|
||||
@ -159,7 +168,9 @@ Future<T> runInContext<T>(
|
||||
Stdio: () => const Stdio(),
|
||||
SystemClock: () => const SystemClock(),
|
||||
TimeoutConfiguration: () => const TimeoutConfiguration(),
|
||||
Usage: () => Usage(),
|
||||
Usage: () => Usage(
|
||||
runningOnBot: runningOnBot,
|
||||
),
|
||||
UserMessages: () => UserMessages(),
|
||||
VisualStudio: () => VisualStudio(),
|
||||
VisualStudioValidator: () => const VisualStudioValidator(),
|
||||
|
@ -6,7 +6,6 @@ import 'dart:async';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../base/bot_detector.dart';
|
||||
import '../base/common.dart';
|
||||
import '../base/context.dart';
|
||||
import '../base/file_system.dart';
|
||||
@ -232,7 +231,7 @@ class _DefaultPub implements Pub {
|
||||
@required bool retry,
|
||||
bool showTraceForErrors,
|
||||
}) async {
|
||||
showTraceForErrors ??= isRunningOnBot(globals.platform);
|
||||
showTraceForErrors ??= await globals.isRunningOnBot;
|
||||
|
||||
String lastPubMessage = 'no message';
|
||||
bool versionSolvingFailed = false;
|
||||
@ -259,7 +258,7 @@ class _DefaultPub implements Pub {
|
||||
_pubCommand(arguments),
|
||||
workingDirectory: directory,
|
||||
mapFunction: filterWrapper, // may set versionSolvingFailed, lastPubMessage
|
||||
environment: _createPubEnvironment(context),
|
||||
environment: await _createPubEnvironment(context),
|
||||
);
|
||||
String message;
|
||||
switch (code) {
|
||||
@ -304,7 +303,7 @@ class _DefaultPub implements Pub {
|
||||
final io.Process process = await processUtils.start(
|
||||
_pubCommand(arguments),
|
||||
workingDirectory: directory,
|
||||
environment: _createPubEnvironment(PubContext.interactive),
|
||||
environment: await _createPubEnvironment(PubContext.interactive),
|
||||
);
|
||||
|
||||
// Pipe the Flutter tool stdin to the pub stdin.
|
||||
@ -348,10 +347,10 @@ typedef MessageFilter = String Function(String message);
|
||||
///
|
||||
/// [context] provides extra information to package server requests to
|
||||
/// understand usage.
|
||||
Map<String, String> _createPubEnvironment(PubContext context) {
|
||||
Future<Map<String, String>> _createPubEnvironment(PubContext context) async {
|
||||
final Map<String, String> environment = <String, String>{
|
||||
'FLUTTER_ROOT': Cache.flutterRoot,
|
||||
_pubEnvironmentKey: _getPubEnvironmentValue(context),
|
||||
_pubEnvironmentKey: await _getPubEnvironmentValue(context),
|
||||
};
|
||||
final String pubCache = _getRootPubCacheIfAvailable();
|
||||
if (pubCache != null) {
|
||||
@ -374,13 +373,13 @@ const String _pubCacheEnvironmentKey = 'PUB_CACHE';
|
||||
///
|
||||
/// [context] provides extra information to package server requests to
|
||||
/// understand usage.
|
||||
String _getPubEnvironmentValue(PubContext pubContext) {
|
||||
Future<String> _getPubEnvironmentValue(PubContext pubContext) async {
|
||||
// DO NOT update this function without contacting kevmoo.
|
||||
// We have server-side tooling that assumes the values are consistent.
|
||||
final String existing = globals.platform.environment[_pubEnvironmentKey];
|
||||
final List<String> values = <String>[
|
||||
if (existing != null && existing.isNotEmpty) existing,
|
||||
if (isRunningOnBot(globals.platform)) 'flutter_bot',
|
||||
if (await globals.isRunningOnBot) 'flutter_bot',
|
||||
'flutter_cli',
|
||||
...pubContext._values,
|
||||
];
|
||||
|
@ -8,12 +8,14 @@ import 'package:process/process.dart';
|
||||
import 'android/android_sdk.dart';
|
||||
import 'android/android_studio.dart';
|
||||
import 'artifacts.dart';
|
||||
import 'base/bot_detector.dart';
|
||||
import 'base/config.dart';
|
||||
import 'base/context.dart';
|
||||
import 'base/error_handling_file_system.dart';
|
||||
import 'base/file_system.dart';
|
||||
import 'base/io.dart';
|
||||
import 'base/logger.dart';
|
||||
import 'base/net.dart';
|
||||
import 'base/os.dart';
|
||||
import 'base/terminal.dart';
|
||||
import 'base/user_messages.dart';
|
||||
@ -65,6 +67,15 @@ Xcode get xcode => context.get<Xcode>();
|
||||
|
||||
XCDevice get xcdevice => context.get<XCDevice>();
|
||||
|
||||
final BotDetector _defaultBotDetector = BotDetector(
|
||||
httpClientFactory: context.get<HttpClientFactory>() ?? () => HttpClient(),
|
||||
platform: platform,
|
||||
);
|
||||
|
||||
BotDetector get botDetector => context.get<BotDetector>() ?? _defaultBotDetector;
|
||||
|
||||
Future<bool> get isRunningOnBot => botDetector.isRunningOnBot;
|
||||
|
||||
/// Display an error level message to the user. Commands should use this if they
|
||||
/// fail in some way.
|
||||
///
|
||||
|
@ -10,7 +10,6 @@ import 'package:http/http.dart' as http;
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:usage/usage_io.dart';
|
||||
|
||||
import '../base/bot_detector.dart';
|
||||
import '../base/context.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/io.dart';
|
||||
|
@ -76,10 +76,12 @@ abstract class Usage {
|
||||
String versionOverride,
|
||||
String configDirOverride,
|
||||
String logFile,
|
||||
@required bool runningOnBot,
|
||||
}) => _DefaultUsage(settingsName: settingsName,
|
||||
versionOverride: versionOverride,
|
||||
configDirOverride: configDirOverride,
|
||||
logFile: logFile);
|
||||
logFile: logFile,
|
||||
runningOnBot: runningOnBot);
|
||||
|
||||
/// Returns [Usage] active in the current app context.
|
||||
static Usage get instance => context.get<Usage>();
|
||||
@ -161,6 +163,7 @@ class _DefaultUsage implements Usage {
|
||||
String versionOverride,
|
||||
String configDirOverride,
|
||||
String logFile,
|
||||
@required bool runningOnBot,
|
||||
}) {
|
||||
final FlutterVersion flutterVersion = globals.flutterVersion;
|
||||
final String version = versionOverride ?? flutterVersion.getVersionString(redactUnknownBranches: true);
|
||||
@ -176,7 +179,7 @@ class _DefaultUsage implements Usage {
|
||||
// Many CI systems don't do a full git checkout.
|
||||
version.endsWith('/unknown') ||
|
||||
// Ignore bots.
|
||||
isRunningOnBot(globals.platform) ||
|
||||
runningOnBot ||
|
||||
// Ignore when suppressed by FLUTTER_SUPPRESS_ANALYTICS.
|
||||
suppressEnvFlag
|
||||
)) {
|
||||
|
@ -25,7 +25,7 @@ class AlwaysTrueBotDetector implements BotDetector {
|
||||
const AlwaysTrueBotDetector();
|
||||
|
||||
@override
|
||||
bool get isRunningOnBot => true;
|
||||
Future<bool> get isRunningOnBot async => true;
|
||||
}
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ class AlwaysFalseBotDetector implements BotDetector {
|
||||
const AlwaysFalseBotDetector();
|
||||
|
||||
@override
|
||||
bool get isRunningOnBot => false;
|
||||
Future<bool> get isRunningOnBot async => false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,6 +69,7 @@ void main() {
|
||||
Usage: () => Usage(
|
||||
configDirOverride: tempDir.path,
|
||||
logFile: tempDir.childFile('analytics.log').path,
|
||||
runningOnBot: true,
|
||||
),
|
||||
});
|
||||
|
||||
@ -91,13 +92,14 @@ void main() {
|
||||
Usage: () => Usage(
|
||||
configDirOverride: tempDir.path,
|
||||
logFile: tempDir.childFile('analytics.log').path,
|
||||
runningOnBot: true,
|
||||
),
|
||||
});
|
||||
|
||||
testUsingContext('Usage records one feature in experiment setting', () async {
|
||||
when<bool>(mockFlutterConfig.getValue(flutterWebFeature.configSetting) as bool)
|
||||
.thenReturn(true);
|
||||
final Usage usage = Usage();
|
||||
final Usage usage = Usage(runningOnBot: true);
|
||||
usage.sendCommand('test');
|
||||
|
||||
final String featuresKey = cdKey(CustomDimensions.enabledFlutterFeatures);
|
||||
@ -119,7 +121,7 @@ void main() {
|
||||
.thenReturn(true);
|
||||
when<bool>(mockFlutterConfig.getValue(flutterMacOSDesktopFeature.configSetting) as bool)
|
||||
.thenReturn(true);
|
||||
final Usage usage = Usage();
|
||||
final Usage usage = Usage(runningOnBot: true);
|
||||
usage.sendCommand('test');
|
||||
|
||||
final String featuresKey = cdKey(CustomDimensions.enabledFlutterFeatures);
|
||||
@ -213,7 +215,10 @@ void main() {
|
||||
mockTimes = <int>[kMillis];
|
||||
// Since FLUTTER_ANALYTICS_LOG_FILE is set in the environment, analytics
|
||||
// will be written to a file.
|
||||
final Usage usage = Usage(versionOverride: 'test');
|
||||
final Usage usage = Usage(
|
||||
versionOverride: 'test',
|
||||
runningOnBot: true,
|
||||
);
|
||||
usage.suppressAnalytics = false;
|
||||
usage.enabled = true;
|
||||
|
||||
@ -239,7 +244,10 @@ void main() {
|
||||
mockTimes = <int>[kMillis];
|
||||
// Since FLUTTER_ANALYTICS_LOG_FILE is set in the environment, analytics
|
||||
// will be written to a file.
|
||||
final Usage usage = Usage(versionOverride: 'test');
|
||||
final Usage usage = Usage(
|
||||
versionOverride: 'test',
|
||||
runningOnBot: true,
|
||||
);
|
||||
usage.suppressAnalytics = false;
|
||||
usage.enabled = true;
|
||||
|
||||
@ -272,7 +280,7 @@ void main() {
|
||||
tryToDelete(tempDir);
|
||||
});
|
||||
|
||||
testUsingContext("don't send on bots", () async {
|
||||
testUsingContext("don't send on bots with unknown version", () async {
|
||||
int count = 0;
|
||||
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
|
||||
|
||||
@ -283,6 +291,7 @@ void main() {
|
||||
settingsName: 'flutter_bot_test',
|
||||
versionOverride: 'dev/unknown',
|
||||
configDirOverride: tempDir.path,
|
||||
runningOnBot: false,
|
||||
),
|
||||
});
|
||||
|
||||
@ -298,6 +307,7 @@ void main() {
|
||||
settingsName: 'flutter_bot_test',
|
||||
versionOverride: 'dev/unknown',
|
||||
configDirOverride: tempDir.path,
|
||||
runningOnBot: false,
|
||||
),
|
||||
});
|
||||
});
|
||||
|
@ -3,6 +3,8 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_tools/src/base/bot_detector.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
@ -12,39 +14,94 @@ void main() {
|
||||
group('BotDetector', () {
|
||||
FakePlatform fakePlatform;
|
||||
MockStdio mockStdio;
|
||||
MockHttpClient mockHttpClient;
|
||||
MockHttpClientRequest mockHttpClientRequest;
|
||||
MockHttpHeaders mockHttpHeaders;
|
||||
BotDetector botDetector;
|
||||
|
||||
setUp(() {
|
||||
fakePlatform = FakePlatform()..environment = <String, String>{};
|
||||
mockStdio = MockStdio();
|
||||
botDetector = BotDetector(platform: fakePlatform);
|
||||
mockHttpClient = MockHttpClient();
|
||||
mockHttpClientRequest = MockHttpClientRequest();
|
||||
mockHttpHeaders = MockHttpHeaders();
|
||||
botDetector = BotDetector(
|
||||
platform: fakePlatform,
|
||||
httpClientFactory: () => mockHttpClient,
|
||||
);
|
||||
});
|
||||
|
||||
group('isRunningOnBot', () {
|
||||
testWithoutContext('returns false unconditionally if BOT=false is set', () async {
|
||||
fakePlatform.environment['BOT'] = 'false';
|
||||
fakePlatform.environment['TRAVIS'] = 'true';
|
||||
expect(botDetector.isRunningOnBot, isFalse);
|
||||
expect(await botDetector.isRunningOnBot, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('returns false unconditionally if FLUTTER_HOST is set', () async {
|
||||
fakePlatform.environment['FLUTTER_HOST'] = 'foo';
|
||||
fakePlatform.environment['TRAVIS'] = 'true';
|
||||
expect(botDetector.isRunningOnBot, isFalse);
|
||||
expect(await botDetector.isRunningOnBot, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('returns false with and without a terminal attached', () async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
throw const SocketException('HTTP connection timed out');
|
||||
});
|
||||
mockStdio.stdout.hasTerminal = true;
|
||||
expect(botDetector.isRunningOnBot, isFalse);
|
||||
expect(await botDetector.isRunningOnBot, isFalse);
|
||||
mockStdio.stdout.hasTerminal = false;
|
||||
expect(botDetector.isRunningOnBot, isFalse);
|
||||
expect(await botDetector.isRunningOnBot, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('can test analytics outputs on bots when outputting to a file', () async {
|
||||
fakePlatform.environment['TRAVIS'] = 'true';
|
||||
fakePlatform.environment['FLUTTER_ANALYTICS_LOG_FILE'] = '/some/file';
|
||||
expect(botDetector.isRunningOnBot, isFalse);
|
||||
expect(await botDetector.isRunningOnBot, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('returns true when azure metadata is reachable', () async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
return Future<HttpClientRequest>.value(mockHttpClientRequest);
|
||||
});
|
||||
when(mockHttpClientRequest.headers).thenReturn(mockHttpHeaders);
|
||||
expect(await botDetector.isRunningOnBot, isTrue);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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 {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
throw const SocketException('HTTP connection timed out');
|
||||
});
|
||||
expect(await azureDetector.isRunningOnAzure, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('isRunningOnAzure returns true when azure metadata is reachable', () async {
|
||||
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
|
||||
return Future<HttpClientRequest>.value(mockHttpClientRequest);
|
||||
});
|
||||
when(mockHttpClientRequest.headers).thenReturn(mockHttpHeaders);
|
||||
expect(await azureDetector.isRunningOnAzure, isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class MockHttpClient extends Mock implements HttpClient {}
|
||||
class MockHttpClientRequest extends Mock implements HttpClientRequest {}
|
||||
class MockHttpHeaders extends Mock implements HttpHeaders {}
|
||||
|
@ -365,7 +365,7 @@ void main() {
|
||||
class BotDetectorAlwaysNo implements BotDetector {
|
||||
const BotDetectorAlwaysNo();
|
||||
@override
|
||||
bool get isRunningOnBot => false;
|
||||
Future<bool> get isRunningOnBot async => false;
|
||||
}
|
||||
|
||||
typedef StartCallback = void Function(List<dynamic> command);
|
||||
|
@ -147,7 +147,10 @@ class CrashingFlutterCommand extends FlutterCommand {
|
||||
}
|
||||
|
||||
class CrashingUsage implements Usage {
|
||||
CrashingUsage() : _impl = Usage(versionOverride: '[user-branch]');
|
||||
CrashingUsage() : _impl = Usage(
|
||||
versionOverride: '[user-branch]',
|
||||
runningOnBot: true,
|
||||
);
|
||||
|
||||
final Usage _impl;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user