Skip to content

Commit 9797d5f

Browse files
authored
[macOS] Refactor the flutter run macOS console output test (#114645)
1 parent 7020f59 commit 9797d5f

File tree

2 files changed

+161
-113
lines changed

2 files changed

+161
-113
lines changed

dev/devicelab/bin/tasks/run_release_test_macos.dart

Lines changed: 3 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -2,122 +2,12 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:async';
6-
import 'dart:convert';
7-
import 'dart:io';
8-
95
import 'package:flutter_devicelab/framework/devices.dart';
106
import 'package:flutter_devicelab/framework/framework.dart';
11-
import 'package:flutter_devicelab/framework/task_result.dart';
12-
import 'package:flutter_devicelab/framework/utils.dart';
13-
import 'package:path/path.dart' as path;
7+
import 'package:flutter_devicelab/tasks/run_tests.dart';
148

159
/// Basic launch test for desktop operating systems.
1610
void main() {
17-
task(() async {
18-
deviceOperatingSystem = DeviceOperatingSystem.macos;
19-
final Device device = await devices.workingDevice;
20-
// TODO(cbracken): https://github.com/flutter/flutter/issues/87508#issuecomment-1043753201
21-
// Switch to dev/integration_tests/ui once we have CocoaPods working on M1 Macs.
22-
final Directory appDir = dir(path.join(flutterDirectory.path, 'examples/hello_world'));
23-
await inDirectory(appDir, () async {
24-
final Completer<void> ready = Completer<void>();
25-
final List<String> stdout = <String>[];
26-
final List<String> stderr = <String>[];
27-
28-
print('run: starting...');
29-
final List<String> options = <String>[
30-
'--release',
31-
'-d',
32-
device.deviceId,
33-
];
34-
final Process run = await startFlutter(
35-
'run',
36-
options: options,
37-
isBot: false,
38-
);
39-
int? runExitCode;
40-
run.stdout
41-
.transform<String>(utf8.decoder)
42-
.transform<String>(const LineSplitter())
43-
.listen((String line) {
44-
print('run:stdout: $line');
45-
if (
46-
!line.startsWith('Building flutter tool...') &&
47-
!line.startsWith('Running "flutter pub get" in ui...') &&
48-
!line.startsWith('Resolving dependencies...') &&
49-
// Catch engine piped output from unrelated concurrent Flutter apps
50-
!line.contains(RegExp(r'[A-Z]\/flutter \([0-9]+\):')) &&
51-
// Empty lines could be due to the progress spinner breaking up.
52-
line.length > 1
53-
) {
54-
stdout.add(line);
55-
}
56-
if (line.contains('Quit (terminate the application on the device).')) {
57-
ready.complete();
58-
}
59-
});
60-
run.stderr
61-
.transform<String>(utf8.decoder)
62-
.transform<String>(const LineSplitter())
63-
.listen((String line) {
64-
print('run:stderr: $line');
65-
stderr.add(line);
66-
});
67-
unawaited(run.exitCode.then<void>((int exitCode) { runExitCode = exitCode; }));
68-
await Future.any<dynamic>(<Future<dynamic>>[ ready.future, run.exitCode ]);
69-
if (runExitCode != null) {
70-
throw 'Failed to run test app; runner unexpected exited, with exit code $runExitCode.';
71-
}
72-
run.stdin.write('q');
73-
74-
await run.exitCode;
75-
76-
_findNextMatcherInList(
77-
stdout,
78-
(String line) => line.startsWith('Launching lib/main.dart on ') && line.endsWith(' in release mode...'),
79-
'Launching lib/main.dart on',
80-
);
81-
82-
_findNextMatcherInList(
83-
stdout,
84-
(String line) => line.contains('Quit (terminate the application on the device).'),
85-
'q Quit (terminate the application on the device)',
86-
);
87-
88-
_findNextMatcherInList(
89-
stdout,
90-
(String line) => line == 'Application finished.',
91-
'Application finished.',
92-
);
93-
});
94-
return TaskResult.success(null);
95-
});
96-
}
97-
98-
void _findNextMatcherInList(
99-
List<String> list,
100-
bool Function(String testLine) matcher,
101-
String errorMessageExpectedLine
102-
) {
103-
final List<String> copyOfListForErrorMessage = List<String>.from(list);
104-
105-
while (list.isNotEmpty) {
106-
final String nextLine = list.first;
107-
list.removeAt(0);
108-
109-
if (matcher(nextLine)) {
110-
return;
111-
}
112-
}
113-
114-
throw '''
115-
Did not find expected line
116-
117-
$errorMessageExpectedLine
118-
119-
in flutter run --release stdout
120-
121-
$copyOfListForErrorMessage
122-
''';
11+
deviceOperatingSystem = DeviceOperatingSystem.macos;
12+
task(createMacOSRunReleaseTest());
12313
}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:async';
6+
import 'dart:convert';
7+
import 'dart:io';
8+
9+
import '../framework/devices.dart';
10+
import '../framework/framework.dart';
11+
import '../framework/task_result.dart';
12+
import '../framework/utils.dart';
13+
14+
TaskFunction createMacOSRunReleaseTest() {
15+
return DesktopRunOutputTest(
16+
// TODO(cbracken): https://github.com/flutter/flutter/issues/87508#issuecomment-1043753201
17+
// Switch to dev/integration_tests/ui once we have CocoaPods working on M1 Macs.
18+
'${flutterDirectory.path}/examples/hello_world',
19+
'lib/main.dart',
20+
release: true,
21+
);
22+
}
23+
24+
class DesktopRunOutputTest extends RunOutputTask {
25+
DesktopRunOutputTest(
26+
super.testDirectory,
27+
super.testTarget, {
28+
required super.release,
29+
}
30+
);
31+
32+
@override
33+
TaskResult verify(List<String> stdout, List<String> stderr) {
34+
_findNextMatcherInList(
35+
stdout,
36+
(String line) => line.startsWith('Launching lib/main.dart on ') &&
37+
line.endsWith(' in ${release ? 'release' : 'debug'} mode...'),
38+
'Launching lib/main.dart on',
39+
);
40+
41+
_findNextMatcherInList(
42+
stdout,
43+
(String line) => line.contains('Quit (terminate the application on the device).'),
44+
'q Quit (terminate the application on the device)',
45+
);
46+
47+
_findNextMatcherInList(
48+
stdout,
49+
(String line) => line == 'Application finished.',
50+
'Application finished.',
51+
);
52+
53+
return TaskResult.success(null);
54+
}
55+
}
56+
57+
/// Test that the output of `flutter run` is expected.
58+
abstract class RunOutputTask {
59+
RunOutputTask(
60+
this.testDirectory,
61+
this.testTarget, {
62+
required this.release,
63+
}
64+
);
65+
66+
/// The directory where the app under test is defined.
67+
final String testDirectory;
68+
/// The main entry-point file of the application, as run on the device.
69+
final String testTarget;
70+
/// Whether to run the app in release mode.
71+
final bool release;
72+
73+
Future<TaskResult> call() {
74+
return inDirectory<TaskResult>(testDirectory, () async {
75+
final Device device = await devices.workingDevice;
76+
await device.unlock();
77+
final String deviceId = device.deviceId;
78+
79+
final Completer<void> ready = Completer<void>();
80+
final List<String> stdout = <String>[];
81+
final List<String> stderr = <String>[];
82+
83+
final List<String> options = <String>[
84+
testTarget,
85+
'-d',
86+
deviceId,
87+
if (release) '--release',
88+
];
89+
90+
final Process run = await startFlutter(
91+
'run',
92+
options: options,
93+
isBot: false,
94+
);
95+
96+
int? runExitCode;
97+
run.stdout
98+
.transform<String>(utf8.decoder)
99+
.transform<String>(const LineSplitter())
100+
.listen((String line) {
101+
print('run:stdout: $line');
102+
stdout.add(line);
103+
if (line.contains('Quit (terminate the application on the device).')) {
104+
ready.complete();
105+
}
106+
});
107+
run.stderr
108+
.transform<String>(utf8.decoder)
109+
.transform<String>(const LineSplitter())
110+
.listen((String line) {
111+
print('run:stderr: $line');
112+
stderr.add(line);
113+
});
114+
unawaited(run.exitCode.then<void>((int exitCode) { runExitCode = exitCode; }));
115+
await Future.any<dynamic>(<Future<dynamic>>[ ready.future, run.exitCode ]);
116+
if (runExitCode != null) {
117+
throw 'Failed to run test app; runner unexpected exited, with exit code $runExitCode.';
118+
}
119+
run.stdin.write('q');
120+
121+
await run.exitCode;
122+
123+
return verify(stdout, stderr);
124+
});
125+
}
126+
127+
/// Verify the output of `flutter run`.
128+
TaskResult verify(List<String> stdout, List<String> stderr) => throw UnimplementedError('verify is not implemented');
129+
130+
/// Helper that verifies a line in [list] matches [matcher].
131+
/// The [list] is updated to contain the lines remaining after the match.
132+
void _findNextMatcherInList(
133+
List<String> list,
134+
bool Function(String testLine) matcher,
135+
String errorMessageExpectedLine
136+
) {
137+
final List<String> copyOfListForErrorMessage = List<String>.from(list);
138+
139+
while (list.isNotEmpty) {
140+
final String nextLine = list.first;
141+
list.removeAt(0);
142+
143+
if (matcher(nextLine)) {
144+
return;
145+
}
146+
}
147+
148+
throw '''
149+
Did not find expected line
150+
151+
$errorMessageExpectedLine
152+
153+
in flutter run ${release ? '--release' : ''} stdout
154+
155+
$copyOfListForErrorMessage
156+
''';
157+
}
158+
}

0 commit comments

Comments
 (0)