Skip to content

Commit a1a801a

Browse files
[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.
1 parent e1e1c36 commit a1a801a

File tree

4 files changed

+116
-35
lines changed

4 files changed

+116
-35
lines changed

packages/flutter_tools/lib/src/ios/core_devices.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,16 @@ class IOSCoreDeviceControl {
7878
];
7979

8080
try {
81-
await _processUtils.run(command, throwOnError: true);
82-
81+
final RunResult result = await _processUtils.run(command, throwOnError: true);
82+
83+
if (!output.existsSync()) {
84+
_logger.printError('After running the command ${command.join(' ')} the file');
85+
_logger.printError('${output.path} was expected to exist, but it did not.');
86+
_logger.printError('The process exited with code ${result.exitCode} and');
87+
_logger.printError('Stdout:\n\n${result.stdout.trim()}\n');
88+
_logger.printError('Stderr:\n\n${result.stderr.trim()}');
89+
throw StateError('Expected the file ${output.path} to exist but it did not');
90+
}
8391
final String stringOutput = output.readAsStringSync();
8492
_logger.printTrace(stringOutput);
8593

packages/flutter_tools/test/general.shard/ios/core_devices_test.dart

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ void main() {
8787
setUp(() {
8888
logger = BufferLogger.test();
8989
fakeProcessManager = FakeProcessManager.empty();
90-
// TODO(fujino): make this FakeProcessManager.empty()
90+
// TODO(fujino): re-use fakeProcessManager
9191
xcode = Xcode.test(processManager: FakeProcessManager.any());
9292
deviceControl = IOSCoreDeviceControl(
9393
logger: logger,
@@ -1355,6 +1355,51 @@ invalid JSON
13551355
expect(fakeProcessManager, hasNoRemainingExpectations);
13561356
});
13571357

1358+
testWithoutContext('Handles json file mysteriously disappearing', () async {
1359+
final Directory tempDir = fileSystem.systemTempDirectory
1360+
.childDirectory('core_devices.rand0');
1361+
final File tempFile = tempDir.childFile('core_device_list.json');
1362+
final List<String> args = <String>[
1363+
'xcrun',
1364+
'devicectl',
1365+
'list',
1366+
'devices',
1367+
'--timeout',
1368+
'5',
1369+
'--json-output',
1370+
tempFile.path,
1371+
];
1372+
fakeProcessManager.addCommand(FakeCommand(
1373+
command: args,
1374+
onRun: (_) {
1375+
// Simulate that this command deleted tempFile, did not create a
1376+
// new one, and exited successfully
1377+
expect(tempFile, exists);
1378+
tempFile.deleteSync();
1379+
expect(tempFile, isNot(exists));
1380+
},
1381+
));
1382+
1383+
await expectLater(
1384+
() => deviceControl.getCoreDevices(),
1385+
throwsA(
1386+
isA<StateError>().having(
1387+
(StateError e) => e.message,
1388+
'message',
1389+
contains('Expected the file ${tempFile.path} to exist but it did not'),
1390+
),
1391+
),
1392+
);
1393+
expect(
1394+
logger.errorText,
1395+
contains('After running the command xcrun devicectl list devices '
1396+
'--timeout 5 --json-output ${tempFile.path} the file\n'
1397+
'${tempFile.path} was expected to exist, but it did not',
1398+
),
1399+
);
1400+
expect(fakeProcessManager, hasNoRemainingExpectations);
1401+
});
1402+
13581403
testWithoutContext('No devices', () async {
13591404
const String deviceControlOutput = '''
13601405
{

packages/flutter_tools/test/integration.shard/overall_experience_test.dart

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,25 @@ void main() {
6666
tryToDelete(fileSystem.directory(tempDirectory));
6767
}
6868
}, skip: Platform.isWindows); // [intended] Windows doesn't support sending signals so we don't care if it can store the PID.
69-
testWithoutContext('flutter run handle SIGUSR1/2', () async {
69+
70+
testWithoutContext('flutter run handle SIGUSR1/2 run', () async {
7071
final String tempDirectory = fileSystem.systemTempDirectory.createTempSync('flutter_overall_experience_test.').resolveSymbolicLinksSync();
7172
final String pidFile = fileSystem.path.join(tempDirectory, 'flutter.pid');
7273
final String testDirectory = fileSystem.path.join(flutterRoot, 'dev', 'integration_tests', 'ui');
7374
final String testScript = fileSystem.path.join('lib', 'commands.dart');
7475
late int pid;
76+
final List<String> command = <String>[
77+
'run',
78+
'-dflutter-tester',
79+
'--report-ready',
80+
'--pid-file',
81+
pidFile,
82+
'--no-devtools',
83+
testScript,
84+
];
7585
try {
7686
final ProcessTestResult result = await runFlutter(
77-
<String>['run', '-dflutter-tester', '--report-ready', '--pid-file', pidFile, '--no-devtools', testScript],
87+
command,
7888
testDirectory,
7989
<Transition>[
8090
Multiple(<Pattern>['Flutter run key commands.', 'called paint'], handler: (String line) {
@@ -108,16 +118,22 @@ void main() {
108118
'called main',
109119
'called paint',
110120
]);
111-
expect(result.stdout.where((String line) => !line.startsWith('called ')), <Object>[
112-
// logs start after we receive the response to sending SIGUSR1
113-
'Performing hot reload...'.padRight(progressMessageWidth),
114-
startsWith('Reloaded 0 libraries in '),
115-
'Performing hot restart...'.padRight(progressMessageWidth),
116-
startsWith('Restarted application in '),
117-
'', // this newline is the one for after we hit "q"
118-
'Application finished.',
119-
'ready',
120-
]);
121+
expect(
122+
result.stdout.where((String line) => !line.startsWith('called ')),
123+
<Object>[
124+
// logs start after we receive the response to sending SIGUSR1
125+
'Performing hot reload...'.padRight(progressMessageWidth),
126+
startsWith('Reloaded 0 libraries in '),
127+
'Performing hot restart...'.padRight(progressMessageWidth),
128+
startsWith('Restarted application in '),
129+
'', // this newline is the one for after we hit "q"
130+
'Application finished.',
131+
'ready',
132+
],
133+
reason: 'stdout from command ${command.join(' ')} was unexpected, '
134+
'full Stdout:\n\n${result.stdout.join('\n')}\n\n'
135+
'Stderr:\n\n${result.stderr.join('\n')}',
136+
);
121137
expect(result.exitCode, 0);
122138
} finally {
123139
tryToDelete(fileSystem.directory(tempDirectory));
@@ -128,9 +144,16 @@ void main() {
128144
final String tempDirectory = fileSystem.systemTempDirectory.createTempSync('flutter_overall_experience_test.').resolveSymbolicLinksSync();
129145
final String testDirectory = fileSystem.path.join(flutterRoot, 'dev', 'integration_tests', 'ui');
130146
final String testScript = fileSystem.path.join('lib', 'commands.dart');
147+
final List<String> command = <String>[
148+
'run',
149+
'-dflutter-tester',
150+
'--report-ready',
151+
'--no-devtools',
152+
testScript,
153+
];
131154
try {
132155
final ProcessTestResult result = await runFlutter(
133-
<String>['run', '-dflutter-tester', '--report-ready', '--no-devtools', testScript],
156+
command,
134157
testDirectory,
135158
<Transition>[
136159
Multiple(<Pattern>['Flutter run key commands.', 'called main', 'called paint'], handler: (String line) {
@@ -171,23 +194,28 @@ void main() {
171194
// debugPaintSizeEnabled = false:
172195
'called paint',
173196
]);
174-
expect(result.stdout.where((String line) => !line.startsWith('called ')), <Object>[
175-
// logs start after we receive the response to hitting "r"
176-
'Performing hot reload...'.padRight(progressMessageWidth),
177-
startsWith('Reloaded 0 libraries in '),
178-
'ready',
179-
'', // this newline is the one for after we hit "R"
180-
'Performing hot restart...'.padRight(progressMessageWidth),
181-
startsWith('Restarted application in '),
182-
'ready',
183-
'', // newline for after we hit "p" the first time
184-
'ready',
185-
'', // newline for after we hit "p" the second time
186-
'ready',
187-
'', // this newline is the one for after we hit "q"
188-
'Application finished.',
189-
'ready',
190-
]);
197+
expect(
198+
result.stdout.where((String line) => !line.startsWith('called ')), <Object>[
199+
// logs start after we receive the response to hitting "r"
200+
'Performing hot reload...'.padRight(progressMessageWidth),
201+
startsWith('Reloaded 0 libraries in '),
202+
'ready',
203+
'', // this newline is the one for after we hit "R"
204+
'Performing hot restart...'.padRight(progressMessageWidth),
205+
startsWith('Restarted application in '),
206+
'ready',
207+
'', // newline for after we hit "p" the first time
208+
'ready',
209+
'', // newline for after we hit "p" the second time
210+
'ready',
211+
'', // this newline is the one for after we hit "q"
212+
'Application finished.',
213+
'ready',
214+
],
215+
reason: 'stdout from command ${command.join(' ')} was unexpected, '
216+
'full Stdout:\n\n${result.stdout.join('\n')}\n\n'
217+
'Stderr:\n\n${result.stderr.join('\n')}',
218+
);
191219
expect(result.exitCode, 0);
192220
} finally {
193221
tryToDelete(fileSystem.directory(tempDirectory));

packages/flutter_tools/test/integration.shard/transition_test_utils.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ Future<ProcessTestResult> runFlutter(
175175
bool debug = false,
176176
bool logging = true,
177177
Duration expectedMaxDuration = const Duration(
178-
minutes:
179-
10), // must be less than test timeout of 15 minutes! See ../../dart_test.yaml.
178+
minutes: 10,
179+
), // must be less than test timeout of 15 minutes! See ../../dart_test.yaml.
180180
}) async {
181181
const LocalPlatform platform = LocalPlatform();
182182
final Stopwatch clock = Stopwatch()..start();

0 commit comments

Comments
 (0)