Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit ec4cfe4

Browse files
authored
Reduce code-duplication a bit and add more error context across SkiaGoldClient. (#51426)
- Replaced manual `StringBuffer()..writeln('stdout: ...')` with a single `SkiaGoldProcessError` constructor. - Updated tests to make sure it's working. _/cc @dnfield @jonahwilliams FYI only._
1 parent dd479bd commit ec4cfe4

File tree

3 files changed

+112
-62
lines changed

3 files changed

+112
-62
lines changed

testing/skia_gold_client/lib/skia_gold_client.dart

Lines changed: 40 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import 'package:meta/meta.dart';
1111
import 'package:path/path.dart' as path;
1212
import 'package:process/process.dart';
1313

14+
import 'src/errors.dart';
15+
16+
export 'src/errors.dart' show SkiaGoldProcessError;
17+
1418
const String _kGoldctlKey = 'GOLDCTL';
1519
const String _kPresubmitEnvName = 'GOLD_TRYJOB';
1620
const String _kLuciEnvName = 'LUCI_CONTEXT';
@@ -154,11 +158,13 @@ interface class SkiaGoldClient {
154158
..writeln('Skia Gold authorization failed.')
155159
..writeln('Luci environments authenticate using the file provided '
156160
'by LUCI_CONTEXT. There may be an error with this file or Gold '
157-
'authentication.')
158-
..writeln('Debug information for Gold:')
159-
..writeln('stdout: ${result.stdout}')
160-
..writeln('stderr: ${result.stderr}');
161-
throw Exception(buf.toString());
161+
'authentication.');
162+
throw SkiaGoldProcessError(
163+
command: authCommand,
164+
stdout: result.stdout.toString(),
165+
stderr: result.stderr.toString(),
166+
message: buf.toString(),
167+
);
162168
} else if (verbose) {
163169
_stderr.writeln('stdout:\n${result.stdout}');
164170
_stderr.writeln('stderr:\n${result.stderr}');
@@ -193,27 +199,19 @@ interface class SkiaGoldClient {
193199
'--passfail',
194200
];
195201

196-
if (imgtestInitCommand.contains(null)) {
197-
final StringBuffer buf = StringBuffer()
198-
..writeln('A null argument was provided for Skia Gold imgtest init.')
199-
..writeln('Please confirm the settings of your golden file test.')
200-
..writeln('Arguments provided:');
201-
imgtestInitCommand.forEach(buf.writeln);
202-
throw Exception(buf.toString());
203-
}
204-
205202
final io.ProcessResult result = await _runCommand(imgtestInitCommand);
206203

207204
if (result.exitCode != 0) {
208205
final StringBuffer buf = StringBuffer()
209206
..writeln('Skia Gold imgtest init failed.')
210207
..writeln('An error occurred when initializing golden file test with ')
211-
..writeln('goldctl.')
212-
..writeln()
213-
..writeln('Debug information for Gold:')
214-
..writeln('stdout: ${result.stdout}')
215-
..writeln('stderr: ${result.stderr}');
216-
throw Exception(buf.toString());
208+
..writeln('goldctl.');
209+
throw SkiaGoldProcessError(
210+
command: imgtestInitCommand,
211+
stdout: result.stdout.toString(),
212+
stderr: result.stderr.toString(),
213+
message: buf.toString(),
214+
);
217215
} else if (verbose) {
218216
_stderr.writeln('stdout:\n${result.stdout}');
219217
_stderr.writeln('stderr:\n${result.stderr}');
@@ -308,12 +306,13 @@ interface class SkiaGoldClient {
308306
..writeln('Visit https://flutter-engine-gold.skia.org/ to view and approve ')
309307
..writeln('the image(s), or revert the associated change. For more ')
310308
..writeln('information, visit the wiki: ')
311-
..writeln('https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter')
312-
..writeln()
313-
..writeln('Debug information for Gold --------------------------------')
314-
..writeln('stdout: ${result.stdout}')
315-
..writeln('stderr: ${result.stderr}');
316-
throw Exception(buf.toString());
309+
..writeln('https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter');
310+
throw SkiaGoldProcessError(
311+
command: imgtestCommand,
312+
stdout: result.stdout.toString(),
313+
stderr: result.stderr.toString(),
314+
message: buf.toString(),
315+
);
317316
} else if (verbose) {
318317
_stderr.writeln('stdout:\n${result.stdout}');
319318
_stderr.writeln('stderr:\n${result.stderr}');
@@ -347,27 +346,19 @@ interface class SkiaGoldClient {
347346
..._getCIArguments(),
348347
];
349348

350-
if (tryjobInitCommand.contains(null)) {
351-
final StringBuffer buf = StringBuffer()
352-
..writeln('A null argument was provided for Skia Gold tryjob init.')
353-
..writeln('Please confirm the settings of your golden file test.')
354-
..writeln('Arguments provided:');
355-
tryjobInitCommand.forEach(buf.writeln);
356-
throw Exception(buf.toString());
357-
}
358-
359349
final io.ProcessResult result = await _runCommand(tryjobInitCommand);
360350

361351
if (result.exitCode != 0) {
362352
final StringBuffer buf = StringBuffer()
363353
..writeln('Skia Gold tryjobInit failure.')
364354
..writeln('An error occurred when initializing golden file tryjob with ')
365-
..writeln('goldctl.')
366-
..writeln()
367-
..writeln('Debug information for Gold:')
368-
..writeln('stdout: ${result.stdout}')
369-
..writeln('stderr: ${result.stderr}');
370-
throw Exception(buf.toString());
355+
..writeln('goldctl.');
356+
throw SkiaGoldProcessError(
357+
command: tryjobInitCommand,
358+
stdout: result.stdout.toString(),
359+
stderr: result.stderr.toString(),
360+
message: buf.toString(),
361+
);
371362
} else if (verbose) {
372363
_stderr.writeln('stdout:\n${result.stdout}');
373364
_stderr.writeln('stderr:\n${result.stderr}');
@@ -414,13 +405,13 @@ interface class SkiaGoldClient {
414405
final StringBuffer buf = StringBuffer()
415406
..writeln('Unexpected Gold tryjobAdd failure.')
416407
..writeln('Tryjob execution for golden file test $testName failed for')
417-
..writeln('a reason unrelated to pixel comparison.')
418-
..writeln()
419-
..writeln('Debug information for Gold:')
420-
..writeln('stdout: ${result.stdout}')
421-
..writeln('stderr: ${result.stderr}')
422-
..writeln();
423-
throw Exception(buf.toString());
408+
..writeln('a reason unrelated to pixel comparison.');
409+
throw SkiaGoldProcessError(
410+
command: tryjobCommand,
411+
stdout: resultStdout,
412+
stderr: result.stderr.toString(),
413+
message: buf.toString(),
414+
);
424415
} else if (verbose) {
425416
_stderr.writeln('stdout:\n${result.stdout}');
426417
_stderr.writeln('stderr:\n${result.stderr}');
@@ -489,7 +480,7 @@ interface class SkiaGoldClient {
489480
workingDirectory: engineCheckout,
490481
);
491482
if (revParse.exitCode != 0) {
492-
throw Exception('Current commit of the engine can not be found from path $engineCheckout.');
483+
throw StateError('Current commit of the engine can not be found from path $engineCheckout.');
493484
}
494485
return (revParse.stdout as String).trim();
495486
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/// Skia Gold errors thrown by intepreting process exits and [stdout]/[stderr].
2+
final class SkiaGoldProcessError extends Error {
3+
/// Creates a new [SkiaGoldProcessError] from the provided origin.
4+
///
5+
/// - [command] is the command that was executed.
6+
/// - [stdout] is the result of the process's standard output.
7+
/// - [stderr] is the result of the process's standard error.
8+
///
9+
/// Optionally, [message] as context for the error.
10+
///
11+
/// ## Example
12+
///
13+
/// ```dart
14+
/// final io.ProcessResult result = await _runCommand(someCommand);
15+
/// if (result.exitCode != 0) {
16+
/// throw SkiaGoldProcessError(
17+
/// command: someCommand,
18+
/// stdout: result.stdout.toString(),
19+
/// stderr: result.stderr.toString(),
20+
/// message: 'Authentication failed <or whatever we were doing>',
21+
/// );
22+
/// }
23+
/// ```
24+
SkiaGoldProcessError({
25+
required Iterable<String> command,
26+
required this.stdout,
27+
required this.stderr,
28+
this.message,
29+
}) : command = List<String>.unmodifiable(command);
30+
31+
/// Optional message to include as context for the error.
32+
final String? message;
33+
34+
/// Command that was executed.
35+
final List<String> command;
36+
37+
/// The result of the process's standard output.
38+
final String stdout;
39+
40+
/// The result of the process's standard error.
41+
final String stderr;
42+
43+
@override
44+
String toString() {
45+
return <String>[
46+
'Error when running Skia Gold: ${command.join(' ')}',
47+
if (message != null) message!,
48+
'',
49+
'stdout: $stdout',
50+
'stderr: $stderr',
51+
].join('\n');
52+
}
53+
}

testing/skia_gold_client/test/skia_gold_client_test.dart

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ void main() {
8080
try {
8181
await client.auth();
8282
fail('auth should fail if GOLDCTL is not set');
83-
} catch (error) {
83+
} on StateError catch (error) {
8484
expect('$error', contains('GOLDCTL is not set'));
8585
}
8686
} finally {
@@ -176,15 +176,17 @@ void main() {
176176
fixture,
177177
environment: presubmitEnv,
178178
onRun: (List<String> command) {
179-
return io.ProcessResult(1, 0, '', 'error-text');
179+
return io.ProcessResult(1, 0, 'stdout-text', 'stderr-text');
180180
},
181181
);
182182

183183
try {
184184
await client.auth();
185-
} catch (error) {
186-
expect('$error', contains('Skia Gold authorization failed.'));
187-
expect('$error', contains('error-text'));
185+
} on SkiaGoldProcessError catch (error) {
186+
expect(error.command, contains('auth'));
187+
expect(error.stdout, 'stdout-text');
188+
expect(error.stderr, 'stderr-text');
189+
expect(error.message, contains('Skia Gold authorization failed'));
188190
}
189191
} finally {
190192
fixture.dispose();
@@ -343,7 +345,7 @@ void main() {
343345
if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) {
344346
return io.ProcessResult(0, 0, '', '');
345347
}
346-
return io.ProcessResult(1, 0, '', 'error-text');
348+
return io.ProcessResult(1, 0, 'stdout-text', 'stderr-text');
347349
},
348350
);
349351

@@ -353,9 +355,11 @@ void main() {
353355
io.File(p.join(fixture.workDirectory.path, 'temp', 'golden.png')),
354356
screenshotSize: 1000,
355357
);
356-
} catch (error) {
357-
expect('$error', contains('Skia Gold image test failed.'));
358-
expect('$error', contains('error-text'));
358+
} on SkiaGoldProcessError catch (error) {
359+
expect(error.message, contains('Skia Gold image test failed.'));
360+
expect(error.stdout, 'stdout-text');
361+
expect(error.stderr, 'stderr-text');
362+
expect(error.command, contains('imgtest add'));
359363
}
360364
} finally {
361365
fixture.dispose();
@@ -470,7 +474,7 @@ void main() {
470474
if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) {
471475
return io.ProcessResult(0, 0, '', '');
472476
}
473-
return io.ProcessResult(1, 0, '', 'error-text');
477+
return io.ProcessResult(1, 0, 'stdout-text', 'stderr-text');
474478
},
475479
);
476480

@@ -480,9 +484,11 @@ void main() {
480484
io.File(p.join(fixture.workDirectory.path, 'temp', 'golden.png')),
481485
screenshotSize: 1000,
482486
);
483-
} catch (error) {
484-
expect('$error', contains('Skia Gold image test failed.'));
485-
expect('$error', contains('error-text'));
487+
} on SkiaGoldProcessError catch (error) {
488+
expect(error.message, contains('Skia Gold image test failed.'));
489+
expect(error.stdout, 'stdout-text');
490+
expect(error.stderr, 'stderr-text');
491+
expect(error.command, contains('imgtest add'));
486492
}
487493
} finally {
488494
fixture.dispose();

0 commit comments

Comments
 (0)