[flutter_tools] add debugging to ios/core_devices.dart (#142187)

Add debugging for #141892 to detect when the temp file mysteriously
disappears after running devicectl.
This commit is contained in:
Christopher Fujino 2024-01-31 15:36:15 -08:00 committed by GitHub
parent e1e1c36d49
commit a1a801a48d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 115 additions and 34 deletions

View file

@ -78,8 +78,16 @@ class IOSCoreDeviceControl {
];
try {
await _processUtils.run(command, throwOnError: true);
final RunResult result = await _processUtils.run(command, throwOnError: true);
if (!output.existsSync()) {
_logger.printError('After running the command ${command.join(' ')} the file');
_logger.printError('${output.path} was expected to exist, but it did not.');
_logger.printError('The process exited with code ${result.exitCode} and');
_logger.printError('Stdout:\n\n${result.stdout.trim()}\n');
_logger.printError('Stderr:\n\n${result.stderr.trim()}');
throw StateError('Expected the file ${output.path} to exist but it did not');
}
final String stringOutput = output.readAsStringSync();
_logger.printTrace(stringOutput);

View file

@ -87,7 +87,7 @@ void main() {
setUp(() {
logger = BufferLogger.test();
fakeProcessManager = FakeProcessManager.empty();
// TODO(fujino): make this FakeProcessManager.empty()
// TODO(fujino): re-use fakeProcessManager
xcode = Xcode.test(processManager: FakeProcessManager.any());
deviceControl = IOSCoreDeviceControl(
logger: logger,
@ -1355,6 +1355,51 @@ invalid JSON
expect(fakeProcessManager, hasNoRemainingExpectations);
});
testWithoutContext('Handles json file mysteriously disappearing', () async {
final Directory tempDir = fileSystem.systemTempDirectory
.childDirectory('core_devices.rand0');
final File tempFile = tempDir.childFile('core_device_list.json');
final List<String> args = <String>[
'xcrun',
'devicectl',
'list',
'devices',
'--timeout',
'5',
'--json-output',
tempFile.path,
];
fakeProcessManager.addCommand(FakeCommand(
command: args,
onRun: (_) {
// Simulate that this command deleted tempFile, did not create a
// new one, and exited successfully
expect(tempFile, exists);
tempFile.deleteSync();
expect(tempFile, isNot(exists));
},
));
await expectLater(
() => deviceControl.getCoreDevices(),
throwsA(
isA<StateError>().having(
(StateError e) => e.message,
'message',
contains('Expected the file ${tempFile.path} to exist but it did not'),
),
),
);
expect(
logger.errorText,
contains('After running the command xcrun devicectl list devices '
'--timeout 5 --json-output ${tempFile.path} the file\n'
'${tempFile.path} was expected to exist, but it did not',
),
);
expect(fakeProcessManager, hasNoRemainingExpectations);
});
testWithoutContext('No devices', () async {
const String deviceControlOutput = '''
{

View file

@ -66,15 +66,25 @@ void main() {
tryToDelete(fileSystem.directory(tempDirectory));
}
}, skip: Platform.isWindows); // [intended] Windows doesn't support sending signals so we don't care if it can store the PID.
testWithoutContext('flutter run handle SIGUSR1/2', () async {
testWithoutContext('flutter run handle SIGUSR1/2 run', () async {
final String tempDirectory = fileSystem.systemTempDirectory.createTempSync('flutter_overall_experience_test.').resolveSymbolicLinksSync();
final String pidFile = fileSystem.path.join(tempDirectory, 'flutter.pid');
final String testDirectory = fileSystem.path.join(flutterRoot, 'dev', 'integration_tests', 'ui');
final String testScript = fileSystem.path.join('lib', 'commands.dart');
late int pid;
final List<String> command = <String>[
'run',
'-dflutter-tester',
'--report-ready',
'--pid-file',
pidFile,
'--no-devtools',
testScript,
];
try {
final ProcessTestResult result = await runFlutter(
<String>['run', '-dflutter-tester', '--report-ready', '--pid-file', pidFile, '--no-devtools', testScript],
command,
testDirectory,
<Transition>[
Multiple(<Pattern>['Flutter run key commands.', 'called paint'], handler: (String line) {
@ -108,16 +118,22 @@ void main() {
'called main',
'called paint',
]);
expect(result.stdout.where((String line) => !line.startsWith('called ')), <Object>[
// logs start after we receive the response to sending SIGUSR1
'Performing hot reload...'.padRight(progressMessageWidth),
startsWith('Reloaded 0 libraries in '),
'Performing hot restart...'.padRight(progressMessageWidth),
startsWith('Restarted application in '),
'', // this newline is the one for after we hit "q"
'Application finished.',
'ready',
]);
expect(
result.stdout.where((String line) => !line.startsWith('called ')),
<Object>[
// logs start after we receive the response to sending SIGUSR1
'Performing hot reload...'.padRight(progressMessageWidth),
startsWith('Reloaded 0 libraries in '),
'Performing hot restart...'.padRight(progressMessageWidth),
startsWith('Restarted application in '),
'', // this newline is the one for after we hit "q"
'Application finished.',
'ready',
],
reason: 'stdout from command ${command.join(' ')} was unexpected, '
'full Stdout:\n\n${result.stdout.join('\n')}\n\n'
'Stderr:\n\n${result.stderr.join('\n')}',
);
expect(result.exitCode, 0);
} finally {
tryToDelete(fileSystem.directory(tempDirectory));
@ -128,9 +144,16 @@ void main() {
final String tempDirectory = fileSystem.systemTempDirectory.createTempSync('flutter_overall_experience_test.').resolveSymbolicLinksSync();
final String testDirectory = fileSystem.path.join(flutterRoot, 'dev', 'integration_tests', 'ui');
final String testScript = fileSystem.path.join('lib', 'commands.dart');
final List<String> command = <String>[
'run',
'-dflutter-tester',
'--report-ready',
'--no-devtools',
testScript,
];
try {
final ProcessTestResult result = await runFlutter(
<String>['run', '-dflutter-tester', '--report-ready', '--no-devtools', testScript],
command,
testDirectory,
<Transition>[
Multiple(<Pattern>['Flutter run key commands.', 'called main', 'called paint'], handler: (String line) {
@ -171,23 +194,28 @@ void main() {
// debugPaintSizeEnabled = false:
'called paint',
]);
expect(result.stdout.where((String line) => !line.startsWith('called ')), <Object>[
// logs start after we receive the response to hitting "r"
'Performing hot reload...'.padRight(progressMessageWidth),
startsWith('Reloaded 0 libraries in '),
'ready',
'', // this newline is the one for after we hit "R"
'Performing hot restart...'.padRight(progressMessageWidth),
startsWith('Restarted application in '),
'ready',
'', // newline for after we hit "p" the first time
'ready',
'', // newline for after we hit "p" the second time
'ready',
'', // this newline is the one for after we hit "q"
'Application finished.',
'ready',
]);
expect(
result.stdout.where((String line) => !line.startsWith('called ')), <Object>[
// logs start after we receive the response to hitting "r"
'Performing hot reload...'.padRight(progressMessageWidth),
startsWith('Reloaded 0 libraries in '),
'ready',
'', // this newline is the one for after we hit "R"
'Performing hot restart...'.padRight(progressMessageWidth),
startsWith('Restarted application in '),
'ready',
'', // newline for after we hit "p" the first time
'ready',
'', // newline for after we hit "p" the second time
'ready',
'', // this newline is the one for after we hit "q"
'Application finished.',
'ready',
],
reason: 'stdout from command ${command.join(' ')} was unexpected, '
'full Stdout:\n\n${result.stdout.join('\n')}\n\n'
'Stderr:\n\n${result.stderr.join('\n')}',
);
expect(result.exitCode, 0);
} finally {
tryToDelete(fileSystem.directory(tempDirectory));

View file

@ -175,8 +175,8 @@ Future<ProcessTestResult> runFlutter(
bool debug = false,
bool logging = true,
Duration expectedMaxDuration = const Duration(
minutes:
10), // must be less than test timeout of 15 minutes! See ../../dart_test.yaml.
minutes: 10,
), // must be less than test timeout of 15 minutes! See ../../dart_test.yaml.
}) async {
const LocalPlatform platform = LocalPlatform();
final Stopwatch clock = Stopwatch()..start();