Unverified Commit 859fce90 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] add feature for iOS, android, and fuchsia (#61481)

Add feature flags for android, ios, and fuchsia (on by default). After updating the g3 rollers, the fuchsia feature will be turned off by default. Creates a simpler base type of feature flags for g3 to extend.

Updates android, ios, fuchsia workflows to use feature flags check.
Removes concept of stable artifacts and checks on flutter version.

Fixes #58999
#52859
#12768
parent 045f3a54
......@@ -40,7 +40,7 @@ class AndroidDevices extends PollingDeviceDiscovery {
final AndroidSdk _androidSdk;
@override
bool get supportsPlatform => true;
bool get supportsPlatform => _androidWorkflow.appliesToHostPlatform;
@override
bool get canListAnything => _androidWorkflow.canListDevices;
......
......@@ -20,6 +20,7 @@ import '../base/utils.dart';
import '../base/version.dart';
import '../convert.dart';
import '../doctor.dart';
import '../features.dart';
import '../globals.dart' as globals;
import 'android_sdk.dart';
import 'android_studio.dart';
......@@ -46,12 +47,15 @@ final RegExp licenseAccepted = RegExp(r'All SDK package licenses accepted.');
class AndroidWorkflow implements Workflow {
AndroidWorkflow({
@required AndroidSdk androidSdk,
}) : _androidSdk = androidSdk;
@required FeatureFlags featureFlags,
}) : _androidSdk = androidSdk,
_featureFlags = featureFlags;
final AndroidSdk _androidSdk;
final FeatureFlags _featureFlags;
@override
bool get appliesToHostPlatform => true;
bool get appliesToHostPlatform => _featureFlags.isAndroidEnabled;
@override
bool get canListDevices => getAdbPath(_androidSdk) != null;
......
......@@ -21,28 +21,25 @@ import 'globals.dart' as globals;
/// A tag for a set of development artifacts that need to be cached.
class DevelopmentArtifact {
const DevelopmentArtifact._(this.name, {this.unstable = false, this.feature});
const DevelopmentArtifact._(this.name, {this.feature});
/// The name of the artifact.
///
/// This should match the flag name in precache.dart
final String name;
/// Whether this artifact should be unavailable on master branch only.
final bool unstable;
/// A feature to control the visibility of this artifact.
final Feature feature;
/// Artifacts required for Android development.
static const DevelopmentArtifact androidGenSnapshot = DevelopmentArtifact._('android_gen_snapshot');
static const DevelopmentArtifact androidMaven = DevelopmentArtifact._('android_maven');
static const DevelopmentArtifact androidGenSnapshot = DevelopmentArtifact._('android_gen_snapshot', feature: flutterAndroidFeature);
static const DevelopmentArtifact androidMaven = DevelopmentArtifact._('android_maven', feature: flutterAndroidFeature);
// Artifacts used for internal builds.
static const DevelopmentArtifact androidInternalBuild = DevelopmentArtifact._('android_internal_build');
static const DevelopmentArtifact androidInternalBuild = DevelopmentArtifact._('android_internal_build', feature: flutterAndroidFeature);
/// Artifacts required for iOS development.
static const DevelopmentArtifact iOS = DevelopmentArtifact._('ios');
static const DevelopmentArtifact iOS = DevelopmentArtifact._('ios', feature: flutterIOSFeature);
/// Artifacts required for web development.
static const DevelopmentArtifact web = DevelopmentArtifact._('web', feature: flutterWebFeature);
......@@ -57,10 +54,10 @@ class DevelopmentArtifact {
static const DevelopmentArtifact linux = DevelopmentArtifact._('linux', feature: flutterLinuxDesktopFeature);
/// Artifacts required for Fuchsia.
static const DevelopmentArtifact fuchsia = DevelopmentArtifact._('fuchsia', unstable: true);
static const DevelopmentArtifact fuchsia = DevelopmentArtifact._('fuchsia', feature: flutterFuchsiaFeature);
/// Artifacts required for the Flutter Runner.
static const DevelopmentArtifact flutterRunner = DevelopmentArtifact._('flutter_runner', unstable: true);
static const DevelopmentArtifact flutterRunner = DevelopmentArtifact._('flutter_runner', feature: flutterFuchsiaFeature);
/// Artifacts required for any development platform.
///
......@@ -84,7 +81,7 @@ class DevelopmentArtifact {
];
@override
String toString() => 'Artifact($name, $unstable)';
String toString() => 'Artifact($name)';
}
/// A wrapper around the `bin/cache/` directory.
......
......@@ -11,9 +11,7 @@ import '../base/logger.dart';
import '../base/platform.dart';
import '../cache.dart';
import '../features.dart';
import '../globals.dart' as globals;
import '../runner/flutter_command.dart';
import '../version.dart';
/// The flutter precache command allows downloading of cache artifacts without
/// the use of device/artifact autodetection.
......@@ -24,12 +22,10 @@ class PrecacheCommand extends FlutterCommand {
@required Platform platform,
@required Logger logger,
@required FeatureFlags featureFlags,
FlutterVersion flutterVersion, // flutter version cannot be injected.
}) : _cache = cache,
_platform = platform,
_logger = logger,
_featureFlags = featureFlags,
_flutterVersion = flutterVersion {
_featureFlags = featureFlags {
argParser.addFlag('all-platforms', abbr: 'a', negatable: false,
help: 'Precache artifacts for all host platforms.');
argParser.addFlag('force', abbr: 'f', negatable: false,
......@@ -70,7 +66,6 @@ class PrecacheCommand extends FlutterCommand {
final Logger _logger;
final Platform _platform;
final FeatureFlags _featureFlags;
final FlutterVersion _flutterVersion;
@override
final String name = 'precache';
......@@ -154,10 +149,6 @@ class PrecacheCommand extends FlutterCommand {
final Map<String, String> umbrellaForArtifact = _umbrellaForArtifactMap();
final Set<DevelopmentArtifact> requiredArtifacts = <DevelopmentArtifact>{};
for (final DevelopmentArtifact artifact in DevelopmentArtifact.values) {
// Don't include unstable artifacts on stable branches.
if (!(_flutterVersion ?? globals.flutterVersion).isMaster && artifact.unstable) {
continue;
}
if (artifact.feature != null && !_featureFlags.isEnabled(artifact.feature)) {
continue;
}
......
......@@ -81,6 +81,7 @@ Future<T> runInContext<T>(
),
AndroidWorkflow: () => AndroidWorkflow(
androidSdk: globals.androidSdk,
featureFlags: featureFlags,
),
ApplicationPackageFactory: () => ApplicationPackageFactory(),
Artifacts: () => CachedArtifacts(
......@@ -149,12 +150,16 @@ Future<T> runInContext<T>(
fileSystem: globals.fs,
androidWorkflow: androidWorkflow,
),
FeatureFlags: () => const FeatureFlags(),
FeatureFlags: () => const FlutterFeatureFlags(),
FlutterVersion: () => FlutterVersion(const SystemClock()),
FuchsiaArtifacts: () => FuchsiaArtifacts.find(),
FuchsiaDeviceTools: () => FuchsiaDeviceTools(),
FuchsiaSdk: () => FuchsiaSdk(),
FuchsiaWorkflow: () => FuchsiaWorkflow(),
FuchsiaWorkflow: () => FuchsiaWorkflow(
featureFlags: featureFlags,
platform: globals.platform,
fuchsiaArtifacts: globals.fuchsiaArtifacts,
),
GradleUtils: () => GradleUtils(),
HotRunnerConfig: () => HotRunnerConfig(),
IOSSimulatorUtils: () => IOSSimulatorUtils(
......@@ -162,7 +167,11 @@ Future<T> runInContext<T>(
processManager: globals.processManager,
xcode: globals.xcode,
),
IOSWorkflow: () => const IOSWorkflow(),
IOSWorkflow: () => IOSWorkflow(
featureFlags: featureFlags,
xcode: globals.xcode,
platform: globals.platform,
),
KernelCompilerFactory: () => KernelCompilerFactory(
logger: globals.logger,
processManager: globals.processManager,
......
......@@ -19,27 +19,68 @@ FeatureFlags get featureFlags => context.get<FeatureFlags>();
/// flags should be provided with a default implementation here. Clients that
/// use this class should extent instead of implement, so that new flags are
/// picked up automatically.
class FeatureFlags {
abstract class FeatureFlags {
/// const constructor so that subclasses can be const.
const FeatureFlags();
/// Whether flutter desktop for linux is enabled.
bool get isLinuxEnabled => isEnabled(flutterLinuxDesktopFeature);
bool get isLinuxEnabled => false;
/// Whether flutter desktop for macOS is enabled.
bool get isMacOSEnabled => isEnabled(flutterMacOSDesktopFeature);
bool get isMacOSEnabled => false;
/// Whether flutter web is enabled.
bool get isWebEnabled => isEnabled(flutterWebFeature);
bool get isWebEnabled => false;
/// Whether flutter desktop for Windows is enabled.
bool get isWindowsEnabled => isEnabled(flutterWindowsDesktopFeature);
bool get isWindowsEnabled => false;
/// Whether android is enabled.
bool get isAndroidEnabled => true;
/// Whether iOS is enabled.
bool get isIOSEnabled => true;
/// Whether fuchsia is enabled.
bool get isFuchsiaEnabled => true;
/// Whether fast single widget reloads are enabled.
bool get isSingleWidgetReloadEnabled => isEnabled(singleWidgetReload);
bool get isSingleWidgetReloadEnabled => false;
/// Whether a particular feature is enabled for the current channel.
///
/// Prefer using one of the specific getters above instead of this API.
bool isEnabled(Feature feature) => false;
}
class FlutterFeatureFlags implements FeatureFlags {
const FlutterFeatureFlags();
@override
bool get isLinuxEnabled => isEnabled(flutterLinuxDesktopFeature);
@override
bool get isMacOSEnabled => isEnabled(flutterMacOSDesktopFeature);
@override
bool get isWebEnabled => isEnabled(flutterWebFeature);
@override
bool get isWindowsEnabled => isEnabled(flutterWindowsDesktopFeature);
@override
bool get isAndroidEnabled => isEnabled(flutterAndroidFeature);
@override
bool get isIOSEnabled => isEnabled(flutterIOSFeature);
@override
bool get isFuchsiaEnabled => isEnabled(flutterFuchsiaFeature);
@override
bool get isSingleWidgetReloadEnabled => isEnabled(singleWidgetReload);
@override
bool isEnabled(Feature feature) {
final String currentChannel = globals.flutterVersion.channel;
final FeatureChannelSetting featureSetting = feature.getSettingForChannel(currentChannel);
......@@ -69,6 +110,9 @@ const List<Feature> allFeatures = <Feature>[
flutterMacOSDesktopFeature,
flutterWindowsDesktopFeature,
singleWidgetReload,
flutterAndroidFeature,
flutterIOSFeature,
flutterFuchsiaFeature,
];
/// The [Feature] for flutter web.
......@@ -131,6 +175,62 @@ const Feature flutterWindowsDesktopFeature = Feature(
),
);
/// The [Feature] for Android devices.
const Feature flutterAndroidFeature = Feature(
name: 'Flutter for Android',
configSetting: 'enable-android',
master: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
dev: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
beta: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
stable: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
);
/// The [Feature] for iOS devices.
const Feature flutterIOSFeature = Feature(
name: 'Flutter for iOS',
configSetting: 'enable-ios',
master: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
dev: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
beta: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
stable: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
);
/// The [Feature] for Fuchsia support.
const Feature flutterFuchsiaFeature = Feature(
name: 'Flutter for Fuchsia',
configSetting: 'enable-fuchsia',
environmentOverride: 'FLUTTER_FUCHSIA',
master: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
);
/// The fast hot reload feature for https://github.com/flutter/flutter/issues/61407.
const Feature singleWidgetReload = Feature(
name: 'Hot reload optimization for changes to class body of a single widget',
......
......@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:meta/meta.dart';
import '../base/context.dart';
import '../base/platform.dart';
import '../doctor.dart';
import '../globals.dart' as globals;
import '../features.dart';
import 'fuchsia_sdk.dart';
/// The [FuchsiaWorkflow] instance.
FuchsiaWorkflow get fuchsiaWorkflow => context.get<FuchsiaWorkflow>();
......@@ -14,18 +18,29 @@ FuchsiaWorkflow get fuchsiaWorkflow => context.get<FuchsiaWorkflow>();
/// This workflow assumes development within the fuchsia source tree,
/// including a working fx command-line tool in the user's PATH.
class FuchsiaWorkflow implements Workflow {
FuchsiaWorkflow({
@required Platform platform,
@required FeatureFlags featureFlags,
@required FuchsiaArtifacts fuchsiaArtifacts,
}) : _platform = platform,
_featureFlags = featureFlags,
_fuchsiaArtifacts = fuchsiaArtifacts;
final Platform _platform;
final FeatureFlags _featureFlags;
final FuchsiaArtifacts _fuchsiaArtifacts;
@override
bool get appliesToHostPlatform => globals.platform.isLinux || globals.platform.isMacOS;
bool get appliesToHostPlatform => _featureFlags.isFuchsiaEnabled && (_platform.isLinux || _platform.isMacOS);
@override
bool get canListDevices {
return globals.fuchsiaArtifacts.devFinder != null;
return _fuchsiaArtifacts.devFinder != null;
}
@override
bool get canLaunchDevices {
return globals.fuchsiaArtifacts.devFinder != null && globals.fuchsiaArtifacts.sshConfig != null;
return _fuchsiaArtifacts.devFinder != null && _fuchsiaArtifacts.sshConfig != null;
}
@override
......
......@@ -2,23 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:meta/meta.dart';
import '../base/platform.dart';
import '../doctor.dart';
import '../globals.dart' as globals;
import '../features.dart';
import '../macos/xcode.dart';
class IOSWorkflow implements Workflow {
const IOSWorkflow();
const IOSWorkflow({
@required Platform platform,
@required FeatureFlags featureFlags,
@required Xcode xcode,
}) : _platform = platform,
_featureFlags = featureFlags,
_xcode = xcode;
final Platform _platform;
final FeatureFlags _featureFlags;
final Xcode _xcode;
@override
bool get appliesToHostPlatform => globals.platform.isMacOS;
bool get appliesToHostPlatform => _featureFlags.isIOSEnabled && _platform.isMacOS;
// We need xcode (+simctl) to list simulator devices, and libimobiledevice to list real devices.
@override
bool get canListDevices => globals.xcode.isInstalledAndMeetsVersionCheck && globals.xcode.isSimctlInstalled;
bool get canListDevices => _xcode.isInstalledAndMeetsVersionCheck && _xcode.isSimctlInstalled;
// We need xcode to launch simulator devices, and ios-deploy
// for real devices.
@override
bool get canLaunchDevices => globals.xcode.isInstalledAndMeetsVersionCheck;
bool get canLaunchDevices => _xcode.isInstalledAndMeetsVersionCheck;
@override
bool get canListEmulators => false;
......
......@@ -7,7 +7,6 @@ import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/precache.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:mockito/mockito.dart';
import '../../src/common.dart';
......@@ -18,8 +17,6 @@ import '../../src/testbed.dart';
void main() {
MockCache cache;
Set<DevelopmentArtifact> artifacts;
MockFlutterVersion flutterVersion;
MockFlutterVersion masterFlutterVersion;
setUp(() {
cache = MockCache();
......@@ -31,10 +28,6 @@ void main() {
artifacts = invocation.positionalArguments.first as Set<DevelopmentArtifact>;
return Future<void>.value(null);
});
flutterVersion = MockFlutterVersion();
when(flutterVersion.isMaster).thenReturn(false);
masterFlutterVersion = MockFlutterVersion();
when(masterFlutterVersion.isMaster).thenReturn(true);
});
testUsingContext('precache should acquire lock', () async {
......@@ -42,7 +35,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
platform: platform,
featureFlags: TestFeatureFlags(),
);
......@@ -65,7 +57,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(),
platform: platform,
);
......@@ -81,7 +72,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(isWebEnabled: true),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -98,7 +88,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(isWebEnabled: false),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -114,7 +103,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(isMacOSEnabled: true),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -131,7 +119,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(isMacOSEnabled: false),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -147,7 +134,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(isWindowsEnabled: true),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -164,7 +150,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(isWindowsEnabled: false),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -180,7 +165,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(isLinuxEnabled: true),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -197,7 +181,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(isLinuxEnabled: false),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -213,7 +196,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(isWebEnabled: false),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -229,7 +211,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: masterFlutterVersion,
featureFlags: TestFeatureFlags(
isWebEnabled: true,
isLinuxEnabled: true,
......@@ -271,7 +252,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -295,7 +275,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -317,44 +296,10 @@ void main() {
}));
});
testUsingContext('precache adds artifact flags to requested artifacts on stable', () async {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(),
platform: FakePlatform(environment: <String, String>{}),
);
applyMocksToCommand(command);
await createTestCommandRunner(command).run(
const <String>[
'precache',
'--ios',
'--android_gen_snapshot',
'--android_maven',
'--android_internal_build',
'--web',
'--macos',
'--linux',
'--windows',
'--fuchsia',
'--flutter_runner',
],
);
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal,
DevelopmentArtifact.iOS,
DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
}));
});
testUsingContext('precache downloads iOS and Android artifacts by default', () async {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -379,7 +324,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: masterFlutterVersion,
featureFlags: TestFeatureFlags(
isWebEnabled: true,
isLinuxEnabled: true,
......@@ -416,7 +360,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: masterFlutterVersion,
featureFlags: TestFeatureFlags(),
platform: FakePlatform(environment: <String, String>{}),
);
......@@ -435,7 +378,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: masterFlutterVersion,
featureFlags: TestFeatureFlags(
isMacOSEnabled: true,
),
......@@ -470,7 +412,6 @@ void main() {
final PrecacheCommand command = PrecacheCommand(
cache: cache,
logger: BufferLogger.test(),
flutterVersion: flutterVersion,
featureFlags: TestFeatureFlags(
isMacOSEnabled: true,
),
......@@ -483,5 +424,4 @@ void main() {
});
}
class MockFlutterVersion extends Mock implements FlutterVersion {}
class MockCache extends Mock implements Cache {}
......@@ -14,6 +14,7 @@ import 'package:mockito/mockito.dart';
import '../../src/common.dart';
import '../../src/fake_process_manager.dart';
import '../../src/testbed.dart';
void main() {
testWithoutContext('AndroidDevices returns empty device list on null adb', () async {
......@@ -22,6 +23,7 @@ void main() {
logger: BufferLogger.test(),
androidWorkflow: AndroidWorkflow(
androidSdk: MockAndroidSdk(null),
featureFlags: TestFeatureFlags(),
),
processManager: FakeProcessManager.list(<FakeCommand>[]),
);
......@@ -43,6 +45,7 @@ void main() {
logger: BufferLogger.test(),
androidWorkflow: AndroidWorkflow(
androidSdk: MockAndroidSdk(),
featureFlags: TestFeatureFlags(),
),
processManager: processManager,
);
......@@ -63,6 +66,7 @@ void main() {
logger: BufferLogger.test(),
androidWorkflow: AndroidWorkflow(
androidSdk: MockAndroidSdk(),
featureFlags: TestFeatureFlags(),
),
processManager: processManager,
);
......@@ -71,6 +75,22 @@ void main() {
throwsToolExit(message: RegExp('Unable to run "adb"')));
});
testWithoutContext('AndroidDevices is disabled if feature is disabled', () {
final AndroidDevices androidDevices = AndroidDevices(
androidSdk: MockAndroidSdk(),
logger: BufferLogger.test(),
androidWorkflow: AndroidWorkflow(
androidSdk: MockAndroidSdk(),
featureFlags: TestFeatureFlags(
isAndroidEnabled: false,
),
),
processManager: FakeProcessManager.any(),
);
expect(androidDevices.supportsPlatform, false);
});
testWithoutContext('physical devices', () {
final List<AndroidDevice> devices = <AndroidDevice>[];
AndroidDevices.parseADBDeviceOutput('''
......
......@@ -261,15 +261,6 @@ void main() {
ProcessManager: () => FakeProcessManager.any(),
});
test('Unstable artifacts', () {
expect(DevelopmentArtifact.web.unstable, false);
expect(DevelopmentArtifact.linux.unstable, false);
expect(DevelopmentArtifact.macOS.unstable, false);
expect(DevelopmentArtifact.windows.unstable, false);
expect(DevelopmentArtifact.fuchsia.unstable, true);
expect(DevelopmentArtifact.flutterRunner.unstable, true);
});
group('EngineCachedArtifact', () {
FakeHttpClient fakeHttpClient;
FakePlatform fakePlatform;
......
......@@ -19,6 +19,7 @@ import 'package:process/process.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
import '../src/testbed.dart';
const FakeEmulator emulator1 = FakeEmulator('Nexus_5', 'Nexus 5', 'Google');
const FakeEmulator emulator2 = FakeEmulator('Nexus_5X_API_27_x86', 'Nexus 5X', 'Google');
......@@ -75,6 +76,7 @@ void main() {
androidSdk: mockSdk,
androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk,
featureFlags: TestFeatureFlags(),
),
);
......@@ -108,6 +110,7 @@ void main() {
androidSdk: mockSdk,
androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk,
featureFlags: TestFeatureFlags(),
),
);
final CreateEmulatorResult result = await emulatorManager.createEmulator();
......@@ -148,6 +151,7 @@ void main() {
androidSdk: mockSdk,
androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk,
featureFlags: TestFeatureFlags(),
),
);
final CreateEmulatorResult result = await emulatorManager.createEmulator();
......@@ -183,6 +187,7 @@ void main() {
androidSdk: mockSdk,
androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk,
featureFlags: TestFeatureFlags(),
),
);
final CreateEmulatorResult result = await emulatorManager.createEmulator(name: 'test');
......@@ -220,6 +225,7 @@ void main() {
androidSdk: mockSdk,
androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk,
featureFlags: TestFeatureFlags(),
),
);
final CreateEmulatorResult result = await emulatorManager.createEmulator(name: 'existing-avd-1');
......@@ -260,6 +266,7 @@ void main() {
androidSdk: mockSdk,
androidWorkflow: AndroidWorkflow(
androidSdk: mockSdk,
featureFlags: TestFeatureFlags(),
),
);
final CreateEmulatorResult result = await emulatorManager.createEmulator();
......
......@@ -26,7 +26,7 @@ void main() {
when(mockPlatform.environment).thenReturn(const <String, String>{});
testbed = Testbed(overrides: <Type, Generator>{
FlutterVersion: () => mockFlutterVerion,
FeatureFlags: () => const FeatureFlags(),
FeatureFlags: () => const FlutterFeatureFlags(),
Config: () => mockFlutterConfig,
Platform: () => mockPlatform,
});
......
......@@ -2,46 +2,85 @@
// 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/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
import 'package:mockito/mockito.dart';
import '../../src/common.dart';
import '../../src/context.dart';
class MockFile extends Mock implements File {}
import '../../src/testbed.dart';
void main() {
group('Fuchsia workflow', () {
final MockFile devFinder = MockFile();
final MockFile sshConfig = MockFile();
when(devFinder.absolute).thenReturn(devFinder);
when(sshConfig.absolute).thenReturn(sshConfig);
testUsingContext('can not list and launch devices if there is not ssh config and dev finder', () {
expect(fuchsiaWorkflow.canLaunchDevices, false);
expect(fuchsiaWorkflow.canListDevices, false);
expect(fuchsiaWorkflow.canListEmulators, false);
}, overrides: <Type, Generator>{
FuchsiaArtifacts: () => FuchsiaArtifacts(devFinder: null, sshConfig: null),
});
testUsingContext('can not list and launch devices if there is not ssh config and dev finder', () {
expect(fuchsiaWorkflow.canLaunchDevices, false);
expect(fuchsiaWorkflow.canListDevices, true);
expect(fuchsiaWorkflow.canListEmulators, false);
}, overrides: <Type, Generator>{
FuchsiaArtifacts: () => FuchsiaArtifacts(devFinder: devFinder, sshConfig: null),
});
testUsingContext('can list and launch devices supported with sufficient SDK artifacts', () {
expect(fuchsiaWorkflow.canLaunchDevices, true);
expect(fuchsiaWorkflow.canListDevices, true);
expect(fuchsiaWorkflow.canListEmulators, false);
}, overrides: <Type, Generator>{
FuchsiaArtifacts: () =>
FuchsiaArtifacts(devFinder: devFinder, sshConfig: sshConfig),
});
final FileSystem fileSystem = MemoryFileSystem.test();
final File devFinder = fileSystem.file('dev_finder');
final File sshConfig = fileSystem.file('ssh_config');
testWithoutContext('Fuchsia workflow does not apply to host platform if feature is disabled', () {
final FuchsiaWorkflow fuchsiaWorkflow = FuchsiaWorkflow(
featureFlags: TestFeatureFlags(isFuchsiaEnabled: false),
fuchsiaArtifacts: FuchsiaArtifacts(devFinder: devFinder, sshConfig: sshConfig),
platform: FakePlatform(operatingSystem: 'linux'),
);
expect(fuchsiaWorkflow.appliesToHostPlatform, false);
});
testWithoutContext('Fuchsia workflow does not apply to host platform on Windows', () {
final FuchsiaWorkflow fuchsiaWorkflow = FuchsiaWorkflow(
featureFlags: TestFeatureFlags(isFuchsiaEnabled: true),
fuchsiaArtifacts: FuchsiaArtifacts(devFinder: devFinder, sshConfig: sshConfig),
platform: FakePlatform(operatingSystem: 'windows'),
);
expect(fuchsiaWorkflow.appliesToHostPlatform, false);
});
testWithoutContext('Fuchsia workflow can not list and launch devices if there is no ssh config and dev finder', () {
final FuchsiaWorkflow fuchsiaWorkflow = FuchsiaWorkflow(
featureFlags: TestFeatureFlags(),
fuchsiaArtifacts: FuchsiaArtifacts(devFinder: null, sshConfig: null),
platform: FakePlatform(operatingSystem: 'linux'),
);
expect(fuchsiaWorkflow.canLaunchDevices, false);
expect(fuchsiaWorkflow.canListDevices, false);
expect(fuchsiaWorkflow.canListEmulators, false);
});
testWithoutContext('Fuchsia workflow can not list and launch devices if there is no ssh config and dev finder', () {
final FuchsiaWorkflow fuchsiaWorkflow = FuchsiaWorkflow(
featureFlags: TestFeatureFlags(),
fuchsiaArtifacts: FuchsiaArtifacts(devFinder: devFinder, sshConfig: null),
platform: FakePlatform(operatingSystem: 'linux'),
);
expect(fuchsiaWorkflow.canLaunchDevices, false);
expect(fuchsiaWorkflow.canListDevices, true);
expect(fuchsiaWorkflow.canListEmulators, false);
});
testWithoutContext('Fuchsia workflow can list and launch devices supported with sufficient SDK artifacts', () {
final FuchsiaWorkflow fuchsiaWorkflow = FuchsiaWorkflow(
featureFlags: TestFeatureFlags(),
fuchsiaArtifacts: FuchsiaArtifacts(devFinder: devFinder, sshConfig: sshConfig),
platform: FakePlatform(operatingSystem: 'linux'),
);
expect(fuchsiaWorkflow.canLaunchDevices, true);
expect(fuchsiaWorkflow.canListDevices, true);
expect(fuchsiaWorkflow.canListEmulators, false);
});
testWithoutContext('Fuchsia workflow can list and launch devices supported with sufficient SDK artifacts on macOS', () {
final FuchsiaWorkflow fuchsiaWorkflow = FuchsiaWorkflow(
featureFlags: TestFeatureFlags(),
fuchsiaArtifacts: FuchsiaArtifacts(devFinder: devFinder, sshConfig: sshConfig),
platform: FakePlatform(operatingSystem: 'macOS'),
);
expect(fuchsiaWorkflow.canLaunchDevices, true);
expect(fuchsiaWorkflow.canListDevices, true);
expect(fuchsiaWorkflow.canListEmulators, false);
});
}
// 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:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/ios/ios_workflow.dart';
import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:mockito/mockito.dart';
import '../../src/common.dart';
import '../../src/testbed.dart';
void main() {
testWithoutContext('iOS workflow is disabled if feature is disabled', () {
final IOSWorkflow iosWorkflow = IOSWorkflow(
platform: FakePlatform(operatingSystem: 'macOS'),
xcode: MockXcode(),
featureFlags: TestFeatureFlags(isIOSEnabled: false),
);
expect(iosWorkflow.appliesToHostPlatform, false);
});
testWithoutContext('iOS workflow is disabled on Linux', () {
final IOSWorkflow iosWorkflow = IOSWorkflow(
platform: FakePlatform(operatingSystem: 'linux'),
xcode: MockXcode(),
featureFlags: TestFeatureFlags(isIOSEnabled: true),
);
expect(iosWorkflow.appliesToHostPlatform, false);
});
testWithoutContext('iOS workflow is disabled on windows', () {
final IOSWorkflow iosWorkflow = IOSWorkflow(
platform: FakePlatform(operatingSystem: 'windows'),
xcode: MockXcode(),
featureFlags: TestFeatureFlags(isIOSEnabled: true),
);
expect(iosWorkflow.appliesToHostPlatform, false);
});
testWithoutContext('iOS workflow is enabled on macOS', () {
final IOSWorkflow iosWorkflow = IOSWorkflow(
platform: FakePlatform(operatingSystem: 'macos'),
xcode: MockXcode(),
featureFlags: TestFeatureFlags(isIOSEnabled: true),
);
expect(iosWorkflow.appliesToHostPlatform, true);
expect(iosWorkflow.canListEmulators, false);
});
testWithoutContext('iOS workflow can launch and list devices when Xcode is set up', () {
final Xcode xcode = MockXcode();
final IOSWorkflow iosWorkflow = IOSWorkflow(
platform: FakePlatform(operatingSystem: 'macos'),
xcode: xcode,
featureFlags: TestFeatureFlags(isIOSEnabled: true),
);
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.isSimctlInstalled).thenReturn(true);
expect(iosWorkflow.canLaunchDevices, true);
expect(iosWorkflow.canListDevices, true);
});
}
class MockXcode extends Mock implements Xcode {}
\ No newline at end of file
......@@ -730,6 +730,9 @@ class TestFeatureFlags implements FeatureFlags {
this.isWebEnabled = false,
this.isWindowsEnabled = false,
this.isSingleWidgetReloadEnabled = false,
this.isAndroidEnabled = true,
this.isIOSEnabled = true,
this.isFuchsiaEnabled = true,
});
@override
......@@ -747,6 +750,15 @@ class TestFeatureFlags implements FeatureFlags {
@override
final bool isSingleWidgetReloadEnabled;
@override
final bool isAndroidEnabled;
@override
final bool isIOSEnabled;
@override
final bool isFuchsiaEnabled;
@override
bool isEnabled(Feature feature) {
switch (feature) {
......@@ -758,6 +770,14 @@ class TestFeatureFlags implements FeatureFlags {
return isMacOSEnabled;
case flutterWindowsDesktopFeature:
return isWindowsEnabled;
case singleWidgetReload:
return isSingleWidgetReloadEnabled;
case flutterAndroidFeature:
return isAndroidEnabled;
case flutterIOSFeature:
return isIOSEnabled;
case flutterFuchsiaFeature:
return isFuchsiaEnabled;
}
return false;
}
......
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