Unverified Commit 1b3fc535 authored by Todd Volkert's avatar Todd Volkert Committed by GitHub

Consider all non-interactive terminals to be bots (#34179)

parent 0bbac725
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
/// increase the API surface that we have to test in Flutter tools, and the APIs /// increase the API surface that we have to test in Flutter tools, and the APIs
/// in `dart:io` can sometimes be hard to use in tests. /// in `dart:io` can sometimes be hard to use in tests.
import 'dart:async'; import 'dart:async';
import 'dart:io' as io show exit, IOSink, ProcessSignal, stderr, stdin, stdout; import 'dart:io' as io show exit, IOSink, ProcessSignal, stderr, stdin, Stdout, stdout;
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
...@@ -72,6 +72,7 @@ export 'dart:io' ...@@ -72,6 +72,7 @@ export 'dart:io'
Stdin, Stdin,
StdinException, StdinException,
// stdout, NO! Use `io.dart` // stdout, NO! Use `io.dart`
Stdout,
Socket, Socket,
SocketException, SocketException,
systemEncoding, systemEncoding,
...@@ -156,7 +157,7 @@ class Stdio { ...@@ -156,7 +157,7 @@ class Stdio {
const Stdio(); const Stdio();
Stream<List<int>> get stdin => io.stdin; Stream<List<int>> get stdin => io.stdin;
io.IOSink get stdout => io.stdout; io.Stdout get stdout => io.stdout;
io.IOSink get stderr => io.stderr; io.IOSink get stderr => io.stderr;
bool get hasTerminal => io.stdout.hasTerminal; bool get hasTerminal => io.stdout.hasTerminal;
...@@ -165,7 +166,7 @@ class Stdio { ...@@ -165,7 +166,7 @@ class Stdio {
bool get supportsAnsiEscapes => hasTerminal ? io.stdout.supportsAnsiEscapes : false; bool get supportsAnsiEscapes => hasTerminal ? io.stdout.supportsAnsiEscapes : false;
} }
Stdio get stdio => context.get<Stdio>(); Stdio get stdio => context.get<Stdio>() ?? const Stdio();
io.IOSink get stdout => stdio.stdout; io.Stdout get stdout => stdio.stdout;
Stream<List<int>> get stdin => stdio.stdin; Stream<List<int>> get stdin => stdio.stdin;
io.IOSink get stderr => stdio.stderr; io.IOSink get stderr => stdio.stderr;
...@@ -21,8 +21,20 @@ class BotDetector { ...@@ -21,8 +21,20 @@ class BotDetector {
const BotDetector(); const BotDetector();
bool get isRunningOnBot { bool get isRunningOnBot {
return platform.environment['BOT'] != 'false' if (
&& (platform.environment['BOT'] == 'true' // 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')
) {
return false;
}
return platform.environment['BOT'] == 'true'
// Non-interactive terminals are assumed to be bots.
|| !io.stdout.hasTerminal
// 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'
...@@ -43,7 +55,8 @@ class BotDetector { ...@@ -43,7 +55,8 @@ class BotDetector {
// 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');
} }
} }
......
// Copyright 2019 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 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/utils.dart';
import 'package:platform/platform.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
void main() {
group('BotDetector', () {
FakePlatform fakePlatform;
MockStdio mockStdio;
BotDetector botDetector;
setUp(() {
fakePlatform = FakePlatform()..environment = <String, String>{};
mockStdio = MockStdio();
botDetector = const BotDetector();
});
group('isRunningOnBot', () {
testUsingContext('returns false unconditionally if BOT=false is set', () async {
fakePlatform.environment['BOT'] = 'false';
fakePlatform.environment['TRAVIS'] = 'true';
expect(botDetector.isRunningOnBot, isFalse);
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Platform: () => fakePlatform,
});
testUsingContext('returns false unconditionally if FLUTTER_HOST is set', () async {
fakePlatform.environment['FLUTTER_HOST'] = 'foo';
fakePlatform.environment['TRAVIS'] = 'true';
expect(botDetector.isRunningOnBot, isFalse);
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Platform: () => fakePlatform,
});
testUsingContext('returns true for non-interactive terminals', () async {
mockStdio.stdout.hasTerminal = true;
expect(botDetector.isRunningOnBot, isFalse);
mockStdio.stdout.hasTerminal = false;
expect(botDetector.isRunningOnBot, isTrue);
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Platform: () => fakePlatform,
});
});
});
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io' as io show IOSink, ProcessSignal; import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException;
import 'package:flutter_tools/src/android/android_device.dart'; import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/android/android_sdk.dart' show AndroidSdk; import 'package:flutter_tools/src/android/android_sdk.dart' show AndroidSdk;
...@@ -342,17 +342,56 @@ class MemoryIOSink implements IOSink { ...@@ -342,17 +342,56 @@ class MemoryIOSink implements IOSink {
Future<void> flush() async { } Future<void> flush() async { }
} }
class MemoryStdout extends MemoryIOSink implements io.Stdout {
@override
bool get hasTerminal => _hasTerminal;
set hasTerminal(bool value) {
assert(value != null);
_hasTerminal = value;
}
bool _hasTerminal = true;
@override
io.IOSink get nonBlocking => this;
@override
bool get supportsAnsiEscapes => _supportsAnsiEscapes;
set supportsAnsiEscapes(bool value) {
assert(value != null);
_supportsAnsiEscapes = value;
}
bool _supportsAnsiEscapes = true;
@override
int get terminalColumns {
if (_terminalColumns != null)
return _terminalColumns;
throw const io.StdoutException('unspecified mock value');
}
set terminalColumns(int value) => _terminalColumns = value;
int _terminalColumns;
@override
int get terminalLines {
if (_terminalLines != null)
return _terminalLines;
throw const io.StdoutException('unspecified mock value');
}
set terminalLines(int value) => _terminalLines = value;
int _terminalLines;
}
/// A Stdio that collects stdout and supports simulated stdin. /// A Stdio that collects stdout and supports simulated stdin.
class MockStdio extends Stdio { class MockStdio extends Stdio {
final MemoryIOSink _stdout = MemoryIOSink(); final MemoryStdout _stdout = MemoryStdout();
final MemoryIOSink _stderr = MemoryIOSink(); final MemoryIOSink _stderr = MemoryIOSink();
final StreamController<List<int>> _stdin = StreamController<List<int>>(); final StreamController<List<int>> _stdin = StreamController<List<int>>();
@override @override
IOSink get stdout => _stdout; MemoryStdout get stdout => _stdout;
@override @override
IOSink get stderr => _stderr; MemoryIOSink get stderr => _stderr;
@override @override
Stream<List<int>> get stdin => _stdin.stream; Stream<List<int>> get stdin => _stdin.stream;
......
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