Implement takeScreenshot and add driver test for Fuchsia (#48611)
This commit is contained in:
parent
52e0d980cb
commit
b9733522dd
@ -0,0 +1,14 @@
|
||||
// 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 'dart:async';
|
||||
|
||||
import 'package:flutter_devicelab/framework/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/tasks/integration_tests.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
deviceOperatingSystem = DeviceOperatingSystem.fuchsia;
|
||||
await task(createFlutterDriverScreenshotTest());
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"program": {
|
||||
"data": "data/flutter_driver_screenshot_test"
|
||||
},
|
||||
"sandbox": {
|
||||
"services": [
|
||||
"fuchsia.cobalt.LoggerFactory",
|
||||
"fuchsia.fonts.Provider",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.modular.Clipboard",
|
||||
"fuchsia.modular.ContextWriter",
|
||||
"fuchsia.modular.DeviceMap",
|
||||
"fuchsia.modular.ModuleContext",
|
||||
"fuchsia.sys.Environment",
|
||||
"fuchsia.sys.Launcher",
|
||||
"fuchsia.testing.runner.TestRunner",
|
||||
"fuchsia.ui.input.ImeService",
|
||||
"fuchsia.ui.policy.Presenter",
|
||||
"fuchsia.ui.scenic.Scenic"
|
||||
]
|
||||
}
|
||||
}
|
@ -71,28 +71,20 @@ class _MyHomePageState extends State<_MyHomePage> {
|
||||
Future<String> _handleDriverMessage(String message) async {
|
||||
switch (message) {
|
||||
case 'device_model':
|
||||
String target;
|
||||
final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
||||
switch (Theme.of(context).platform) {
|
||||
case TargetPlatform.iOS:
|
||||
target = 'ios';
|
||||
break;
|
||||
case TargetPlatform.android:
|
||||
target = 'android';
|
||||
break;
|
||||
default:
|
||||
target = 'unsupported';
|
||||
break;
|
||||
}
|
||||
final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
||||
if (target == 'ios') {
|
||||
final IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo;
|
||||
if (iosDeviceInfo.isPhysicalDevice) {
|
||||
return iosDeviceInfo.utsname.machine;
|
||||
} else {
|
||||
final IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo;
|
||||
if (iosDeviceInfo.isPhysicalDevice) {
|
||||
return iosDeviceInfo.utsname.machine;
|
||||
}
|
||||
return 'sim_' + iosDeviceInfo.name;
|
||||
}
|
||||
} else if (target == 'android') {
|
||||
return (await deviceInfo.androidInfo).model;
|
||||
case TargetPlatform.android:
|
||||
return (await deviceInfo.androidInfo).model;
|
||||
case TargetPlatform.fuchsia:
|
||||
return 'fuchsia';
|
||||
default:
|
||||
return 'unsupported';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class FuchsiaDevices extends PollingDeviceDiscovery {
|
||||
FuchsiaDevices() : super('Fuchsia devices');
|
||||
|
||||
@override
|
||||
bool get supportsPlatform => globals.platform.isLinux || globals.platform.isMacOS;
|
||||
bool get supportsPlatform => isFuchsiaSupportedPlatform();
|
||||
|
||||
@override
|
||||
bool get canListAnything => fuchsiaWorkflow.canListDevices;
|
||||
@ -442,6 +442,39 @@ class FuchsiaDevice extends Device {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool get supportsScreenshot => isFuchsiaSupportedPlatform();
|
||||
|
||||
@override
|
||||
Future<void> takeScreenshot(File outputFile) async {
|
||||
if (outputFile.basename.split('.').last != 'ppm') {
|
||||
throw '${outputFile.path} must be a .ppm file';
|
||||
}
|
||||
final RunResult screencapResult = await shell('screencap > /tmp/screenshot.ppm');
|
||||
if (screencapResult.exitCode != 0) {
|
||||
throw 'Could not take a screenshot on device $name:\n$screencapResult';
|
||||
}
|
||||
try {
|
||||
final RunResult scpResult = await scp('/tmp/screenshot.ppm', outputFile.path);
|
||||
if (scpResult.exitCode != 0) {
|
||||
throw 'Failed to copy screenshot from device:\n$scpResult';
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
final RunResult deleteResult = await shell('rm /tmp/screenshot.ppm');
|
||||
if (deleteResult.exitCode != 0) {
|
||||
globals.printError(
|
||||
'Failed to delete screenshot.ppm from the device:\n$deleteResult'
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
globals.printError(
|
||||
'Failed to delete screenshot.ppm from the device'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async => _targetPlatform ??= await _queryTargetPlatform();
|
||||
|
||||
@ -479,9 +512,6 @@ class FuchsiaDevice extends Device {
|
||||
@override
|
||||
void clearLogs() {}
|
||||
|
||||
@override
|
||||
bool get supportsScreenshot => false;
|
||||
|
||||
bool get ipv6 {
|
||||
try {
|
||||
Uri.parseIPv6Address(id);
|
||||
@ -545,6 +575,21 @@ class FuchsiaDevice extends Device {
|
||||
]);
|
||||
}
|
||||
|
||||
/// Transfer the file [origin] from the device to [destination].
|
||||
Future<RunResult> scp(String origin, String destination) async {
|
||||
if (fuchsiaArtifacts.sshConfig == null) {
|
||||
throwToolExit('Cannot interact with device. No ssh config.\n'
|
||||
'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.');
|
||||
}
|
||||
return await processUtils.run(<String>[
|
||||
'scp',
|
||||
'-F',
|
||||
fuchsiaArtifacts.sshConfig.absolute.path,
|
||||
'$id:$origin',
|
||||
destination,
|
||||
]);
|
||||
}
|
||||
|
||||
/// Finds the first port running a VM matching `isolateName` from the
|
||||
/// provided set of `ports`.
|
||||
///
|
||||
|
@ -20,6 +20,11 @@ FuchsiaSdk get fuchsiaSdk => context.get<FuchsiaSdk>();
|
||||
/// The [FuchsiaArtifacts] instance.
|
||||
FuchsiaArtifacts get fuchsiaArtifacts => context.get<FuchsiaArtifacts>();
|
||||
|
||||
/// Returns [true] if the current platform supports Fuchsia targets.
|
||||
bool isFuchsiaSupportedPlatform() {
|
||||
return globals.platform.isLinux || globals.platform.isMacOS;
|
||||
}
|
||||
|
||||
/// The Fuchsia SDK shell commands.
|
||||
///
|
||||
/// This workflow assumes development within the fuchsia source tree,
|
||||
@ -110,7 +115,7 @@ class FuchsiaArtifacts {
|
||||
/// FUCHSIA_SSH_CONFIG) to find the ssh configuration needed to talk to
|
||||
/// a device.
|
||||
factory FuchsiaArtifacts.find() {
|
||||
if (!globals.platform.isLinux && !globals.platform.isMacOS) {
|
||||
if (!isFuchsiaSupportedPlatform()) {
|
||||
// Don't try to find the artifacts on platforms that are not supported.
|
||||
return FuchsiaArtifacts();
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import 'package:flutter_tools/src/vmservice.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:process/process.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
@ -325,6 +326,230 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
group('screenshot', () {
|
||||
MockProcessManager mockProcessManager;
|
||||
|
||||
setUp(() {
|
||||
mockProcessManager = MockProcessManager();
|
||||
});
|
||||
|
||||
test('is supported on posix platforms', () {
|
||||
final FuchsiaDevice device = FuchsiaDevice('id', name: 'tester');
|
||||
expect(device.supportsScreenshot, true);
|
||||
}, testOn: 'posix');
|
||||
|
||||
testUsingContext('is not supported on Windows', () {
|
||||
final FuchsiaDevice device = FuchsiaDevice('id', name: 'tester');
|
||||
expect(device.supportsScreenshot, false);
|
||||
}, overrides: <Type, Generator>{
|
||||
Platform: () => FakePlatform(
|
||||
operatingSystem: 'windows',
|
||||
),
|
||||
});
|
||||
|
||||
test('takeScreenshot throws if file isn\'t .ppm', () async {
|
||||
final FuchsiaDevice device = FuchsiaDevice('id', name: 'tester');
|
||||
await expectLater(
|
||||
() => device.takeScreenshot(globals.fs.file('file.invalid')),
|
||||
throwsA(equals('file.invalid must be a .ppm file')),
|
||||
);
|
||||
}, testOn: 'posix');
|
||||
|
||||
testUsingContext('takeScreenshot throws if screencap failed', () async {
|
||||
final FuchsiaDevice device = FuchsiaDevice('0.0.0.0', name: 'tester');
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'ssh',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0',
|
||||
'screencap > /tmp/screenshot.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 1, '', '<error-message>'));
|
||||
|
||||
await expectLater(
|
||||
() => device.takeScreenshot(globals.fs.file('file.ppm')),
|
||||
throwsA(equals('Could not take a screenshot on device tester:\n<error-message>')),
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
Platform: () => FakePlatform(
|
||||
environment: <String, String>{
|
||||
'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh',
|
||||
},
|
||||
operatingSystem: 'linux',
|
||||
),
|
||||
}, testOn: 'posix');
|
||||
|
||||
testUsingContext('takeScreenshot throws if scp failed', () async {
|
||||
final FuchsiaDevice device = FuchsiaDevice('0.0.0.0', name: 'tester');
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'ssh',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0',
|
||||
'screencap > /tmp/screenshot.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 0, '', ''));
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'scp',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0:/tmp/screenshot.ppm',
|
||||
'file.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 1, '', '<error-message>'));
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'ssh',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0',
|
||||
'rm /tmp/screenshot.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 0, '', ''));
|
||||
|
||||
await expectLater(
|
||||
() => device.takeScreenshot(globals.fs.file('file.ppm')),
|
||||
throwsA(equals('Failed to copy screenshot from device:\n<error-message>')),
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
Platform: () => FakePlatform(
|
||||
environment: <String, String>{
|
||||
'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh',
|
||||
},
|
||||
operatingSystem: 'linux',
|
||||
),
|
||||
}, testOn: 'posix');
|
||||
|
||||
testUsingContext('takeScreenshot prints error if can\'t delete file from device', () async {
|
||||
final FuchsiaDevice device = FuchsiaDevice('0.0.0.0', name: 'tester');
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'ssh',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0',
|
||||
'screencap > /tmp/screenshot.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 0, '', ''));
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'scp',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0:/tmp/screenshot.ppm',
|
||||
'file.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 0, '', ''));
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'ssh',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0',
|
||||
'rm /tmp/screenshot.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 1, '', '<error-message>'));
|
||||
|
||||
try {
|
||||
await device.takeScreenshot(globals.fs.file('file.ppm'));
|
||||
} catch (_) {
|
||||
assert(false);
|
||||
}
|
||||
expect(
|
||||
testLogger.errorText,
|
||||
contains('Failed to delete screenshot.ppm from the device:\n<error-message>'),
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
Platform: () => FakePlatform(
|
||||
environment: <String, String>{
|
||||
'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh',
|
||||
},
|
||||
operatingSystem: 'linux',
|
||||
),
|
||||
}, testOn: 'posix');
|
||||
|
||||
testUsingContext('takeScreenshot returns', () async {
|
||||
final FuchsiaDevice device = FuchsiaDevice('0.0.0.0', name: 'tester');
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'ssh',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0',
|
||||
'screencap > /tmp/screenshot.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 0, '', ''));
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'scp',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0:/tmp/screenshot.ppm',
|
||||
'file.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 0, '', ''));
|
||||
|
||||
when(mockProcessManager.run(
|
||||
const <String>[
|
||||
'ssh',
|
||||
'-F',
|
||||
'/fuchsia/out/default/.ssh',
|
||||
'0.0.0.0',
|
||||
'rm /tmp/screenshot.ppm',
|
||||
],
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
environment: anyNamed('environment'),
|
||||
)).thenAnswer((_) async => ProcessResult(0, 0, '', ''));
|
||||
|
||||
try {
|
||||
await device.takeScreenshot(globals.fs.file('file.ppm'));
|
||||
} catch (_) {
|
||||
assert(false);
|
||||
}
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
Platform: () => FakePlatform(
|
||||
environment: <String, String>{
|
||||
'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh',
|
||||
},
|
||||
operatingSystem: 'linux',
|
||||
),
|
||||
}, testOn: 'posix');
|
||||
});
|
||||
|
||||
group(FuchsiaIsolateDiscoveryProtocol, () {
|
||||
MockPortForwarder portForwarder;
|
||||
MockVMService vmService;
|
||||
|
Loading…
x
Reference in New Issue
Block a user