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 @@
/// 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.
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';
......@@ -72,6 +72,7 @@ export 'dart:io'
Stdin,
StdinException,
// stdout, NO! Use `io.dart`
Stdout,
Socket,
SocketException,
systemEncoding,
......@@ -156,7 +157,7 @@ class Stdio {
const Stdio();
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;
bool get hasTerminal => io.stdout.hasTerminal;
......@@ -165,7 +166,7 @@ class Stdio {
bool get supportsAnsiEscapes => hasTerminal ? io.stdout.supportsAnsiEscapes : false;
}
Stdio get stdio => context.get<Stdio>();
io.IOSink get stdout => stdio.stdout;
Stdio get stdio => context.get<Stdio>() ?? const Stdio();
io.Stdout get stdout => stdio.stdout;
Stream<List<int>> get stdin => stdio.stdin;
io.IOSink get stderr => stdio.stderr;
......@@ -21,8 +21,20 @@ class BotDetector {
const BotDetector();
bool get isRunningOnBot {
return platform.environment['BOT'] != 'false'
&& (platform.environment['BOT'] == 'true'
if (
// 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
|| platform.environment['TRAVIS'] == 'true'
......@@ -43,7 +55,8 @@ class BotDetector {
// Properties on Flutter's Chrome Infra bots.
|| 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 @@
import 'dart:async';
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_sdk.dart' show AndroidSdk;
......@@ -342,17 +342,56 @@ class MemoryIOSink implements IOSink {
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.
class MockStdio extends Stdio {
final MemoryIOSink _stdout = MemoryIOSink();
final MemoryStdout _stdout = MemoryStdout();
final MemoryIOSink _stderr = MemoryIOSink();
final StreamController<List<int>> _stdin = StreamController<List<int>>();
@override
IOSink get stdout => _stdout;
MemoryStdout get stdout => _stdout;
@override
IOSink get stderr => _stderr;
MemoryIOSink get stderr => _stderr;
@override
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