Unverified Commit 1903ce01 authored by Zachary Anderson's avatar Zachary Anderson Committed by GitHub

Revert "[flutter_tools] Disable analytics for more bots (#50579)" (#50622)

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