// Copyright 2014 The Flutter 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:file/memory.dart'; import 'package:flutter_tools/src/base/bot_detector.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/persistent_tool_state.dart'; import '../../src/common.dart'; import '../../src/fake_http_client.dart'; import '../../src/fakes.dart'; final Uri azureUrl = Uri.parse('http://169.254.169.254/metadata/instance'); void main() { group('BotDetector', () { late FakePlatform fakePlatform; late FakeStdio fakeStdio; late PersistentToolState persistentToolState; setUp(() { fakePlatform = FakePlatform()..environment = <String, String>{}; fakeStdio = FakeStdio(); persistentToolState = PersistentToolState.test( directory: MemoryFileSystem.test().currentDirectory, logger: BufferLogger.test(), ); }); group('isRunningOnBot', () { testWithoutContext('returns false unconditionally if BOT=false is set', () async { fakePlatform.environment['BOT'] = 'false'; fakePlatform.environment['TRAVIS'] = 'true'; final BotDetector botDetector = BotDetector( platform: fakePlatform, httpClientFactory: () => FakeHttpClient.any(), persistentToolState: persistentToolState, ); expect(await botDetector.isRunningOnBot, isFalse); expect(persistentToolState.isRunningOnBot, isFalse); }); testWithoutContext('does not cache BOT environment variable', () async { fakePlatform.environment['BOT'] = 'true'; final BotDetector botDetector = BotDetector( platform: fakePlatform, httpClientFactory: () => FakeHttpClient.any(), persistentToolState: persistentToolState, ); expect(await botDetector.isRunningOnBot, isTrue); expect(persistentToolState.isRunningOnBot, isTrue); fakePlatform.environment['BOT'] = 'false'; expect(await botDetector.isRunningOnBot, isFalse); expect(persistentToolState.isRunningOnBot, isFalse); }); testWithoutContext('returns false unconditionally if FLUTTER_HOST is set', () async { fakePlatform.environment['FLUTTER_HOST'] = 'foo'; fakePlatform.environment['TRAVIS'] = 'true'; final BotDetector botDetector = BotDetector( platform: fakePlatform, httpClientFactory: () => FakeHttpClient.any(), persistentToolState: persistentToolState, ); expect(await botDetector.isRunningOnBot, isFalse); expect(persistentToolState.isRunningOnBot, isFalse); }); testWithoutContext('returns false with and without a terminal attached', () async { final BotDetector botDetector = BotDetector( platform: fakePlatform, httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[ FakeRequest(azureUrl, responseError: const SocketException('HTTP connection timed out')), ]), persistentToolState: persistentToolState, ); fakeStdio.stdout.hasTerminal = true; expect(await botDetector.isRunningOnBot, isFalse); fakeStdio.stdout.hasTerminal = false; expect(await botDetector.isRunningOnBot, isFalse); expect(persistentToolState.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'; final BotDetector botDetector = BotDetector( platform: fakePlatform, httpClientFactory: () => FakeHttpClient.any(), persistentToolState: persistentToolState, ); expect(await botDetector.isRunningOnBot, isFalse); expect(persistentToolState.isRunningOnBot, isFalse); }); testWithoutContext('returns true when azure metadata is reachable', () async { final BotDetector botDetector = BotDetector( platform: fakePlatform, httpClientFactory: () => FakeHttpClient.any(), persistentToolState: persistentToolState, ); expect(await botDetector.isRunningOnBot, isTrue); expect(persistentToolState.isRunningOnBot, isTrue); }); testWithoutContext('caches azure bot detection results across instances', () async { final BotDetector botDetector = BotDetector( platform: fakePlatform, httpClientFactory: () => FakeHttpClient.any(), persistentToolState: persistentToolState, ); expect(await botDetector.isRunningOnBot, isTrue); expect(await BotDetector( platform: fakePlatform, httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[]), persistentToolState: persistentToolState, ).isRunningOnBot, isTrue); }); testWithoutContext('returns true when running on borg', () async { fakePlatform.environment['BORG_ALLOC_DIR'] = 'true'; final BotDetector botDetector = BotDetector( platform: fakePlatform, httpClientFactory: () => FakeHttpClient.any(), persistentToolState: persistentToolState, ); expect(await botDetector.isRunningOnBot, isTrue); expect(persistentToolState.isRunningOnBot, isTrue); }); }); }); group('AzureDetector', () { testWithoutContext('isRunningOnAzure returns false when connection times out', () async { final AzureDetector azureDetector = AzureDetector( httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[ FakeRequest(azureUrl, responseError: const SocketException('HTTP connection timed out')), ], )); expect(await azureDetector.isRunningOnAzure, isFalse); }); testWithoutContext('isRunningOnAzure returns false when OsError is thrown', () async { final AzureDetector azureDetector = AzureDetector( httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[ FakeRequest(azureUrl, responseError: const OSError('Connection Refused', 111)), ], )); expect(await azureDetector.isRunningOnAzure, isFalse); }); testWithoutContext('isRunningOnAzure returns true when azure metadata is reachable', () async { final AzureDetector azureDetector = AzureDetector( httpClientFactory: () => FakeHttpClient.list(<FakeRequest>[ FakeRequest(azureUrl), ], )); expect(await azureDetector.isRunningOnAzure, isTrue); }); }); }