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 {
|
Future<String> _handleDriverMessage(String message) async {
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case 'device_model':
|
case 'device_model':
|
||||||
String target;
|
final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
||||||
switch (Theme.of(context).platform) {
|
switch (Theme.of(context).platform) {
|
||||||
case TargetPlatform.iOS:
|
case TargetPlatform.iOS:
|
||||||
target = 'ios';
|
final IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo;
|
||||||
break;
|
if (iosDeviceInfo.isPhysicalDevice) {
|
||||||
case TargetPlatform.android:
|
return iosDeviceInfo.utsname.machine;
|
||||||
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 {
|
|
||||||
return 'sim_' + iosDeviceInfo.name;
|
return 'sim_' + iosDeviceInfo.name;
|
||||||
}
|
case TargetPlatform.android:
|
||||||
} else if (target == 'android') {
|
return (await deviceInfo.androidInfo).model;
|
||||||
return (await deviceInfo.androidInfo).model;
|
case TargetPlatform.fuchsia:
|
||||||
|
return 'fuchsia';
|
||||||
|
default:
|
||||||
|
return 'unsupported';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ class FuchsiaDevices extends PollingDeviceDiscovery {
|
|||||||
FuchsiaDevices() : super('Fuchsia devices');
|
FuchsiaDevices() : super('Fuchsia devices');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get supportsPlatform => globals.platform.isLinux || globals.platform.isMacOS;
|
bool get supportsPlatform => isFuchsiaSupportedPlatform();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get canListAnything => fuchsiaWorkflow.canListDevices;
|
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
|
@override
|
||||||
Future<TargetPlatform> get targetPlatform async => _targetPlatform ??= await _queryTargetPlatform();
|
Future<TargetPlatform> get targetPlatform async => _targetPlatform ??= await _queryTargetPlatform();
|
||||||
|
|
||||||
@ -479,9 +512,6 @@ class FuchsiaDevice extends Device {
|
|||||||
@override
|
@override
|
||||||
void clearLogs() {}
|
void clearLogs() {}
|
||||||
|
|
||||||
@override
|
|
||||||
bool get supportsScreenshot => false;
|
|
||||||
|
|
||||||
bool get ipv6 {
|
bool get ipv6 {
|
||||||
try {
|
try {
|
||||||
Uri.parseIPv6Address(id);
|
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
|
/// Finds the first port running a VM matching `isolateName` from the
|
||||||
/// provided set of `ports`.
|
/// provided set of `ports`.
|
||||||
///
|
///
|
||||||
|
@ -20,6 +20,11 @@ FuchsiaSdk get fuchsiaSdk => context.get<FuchsiaSdk>();
|
|||||||
/// The [FuchsiaArtifacts] instance.
|
/// The [FuchsiaArtifacts] instance.
|
||||||
FuchsiaArtifacts get fuchsiaArtifacts => context.get<FuchsiaArtifacts>();
|
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.
|
/// The Fuchsia SDK shell commands.
|
||||||
///
|
///
|
||||||
/// This workflow assumes development within the fuchsia source tree,
|
/// 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
|
/// FUCHSIA_SSH_CONFIG) to find the ssh configuration needed to talk to
|
||||||
/// a device.
|
/// a device.
|
||||||
factory FuchsiaArtifacts.find() {
|
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.
|
// Don't try to find the artifacts on platforms that are not supported.
|
||||||
return FuchsiaArtifacts();
|
return FuchsiaArtifacts();
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import 'package:flutter_tools/src/vmservice.dart';
|
|||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
import 'package:process/process.dart';
|
import 'package:process/process.dart';
|
||||||
|
import 'package:platform/platform.dart';
|
||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
import '../../src/context.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, () {
|
group(FuchsiaIsolateDiscoveryProtocol, () {
|
||||||
MockPortForwarder portForwarder;
|
MockPortForwarder portForwarder;
|
||||||
MockVMService vmService;
|
MockVMService vmService;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user