Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Allow marking a golden check as flaky #113396

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

yjbanov
Copy link
Contributor

@yjbanov yjbanov commented Oct 13, 2022

(this is a non-breaking non-API-changing variant of #111595)

Support marking a golden check as flaky. A flaky check will still generate a golden and report it to the current GoldenFileComparator, but it will not fail the test.

Public API changes

In order to keep the concept of "flaky golden" private to the Flutter repo, the public golden test API was extended in the following non-breaking ways:

Private changes

The following changes do not affect the public API:

TODO

  • We have a check in the analyzer that ensures every matchesGoldenFile has a Tag at the top of the test file. It should probably be updated to ensure uses of matchesFlutterGolden are accounted for.
  • We'd probably want to migrate all uses of matchesGoldenFile in the framework tests to use this one for consistency, and have the analyzer enforce it.
  • Document the new flutter_web_test_config.dart file.
  • Add tests for isFlaky and new public API.

Fixes #111325

@flutter-dashboard flutter-dashboard bot added a: tests "flutter test", flutter_test, or one of our tests a: text input Entering text in a text field or keyboard related problems d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos documentation f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels. c: contributor-productivity Team-specific productivity, code health, technical debt. tool Affects the "flutter" command-line tool. See also t: labels. labels Oct 13, 2022
@yjbanov yjbanov force-pushed the flaky-golden-api-2 branch 3 times, most recently from 0add2ea to cbf2318 Compare October 17, 2022 23:47
@yjbanov yjbanov requested a review from Piinks October 18, 2022 20:21
@yjbanov
Copy link
Contributor Author

yjbanov commented Oct 18, 2022

@Piinks the PR lacks documentation and tests. At this point I'm looking for an initial design review. Didn't want to spend time on minutiae without a high-level agreement first.

}
}

Future<GoldenFileComparator> _createComparator({ bool isFlaky = false }) async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the comparator need to know if something is flaky? Couldn't it just be a flag on compare? IIRC, we create a comparator for each test file, not each individual test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my proposal in the previous PR, but that change turned out to be breaking and it made the isFlaky flag public, both aspects considered undesirable in review comments. However, I'm not against that approach. It will just require a small migration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I meant the compare of the super class of Flutter's specific comparator (FlutterGoldenFileComparator).. not the public GoldenFileComparator.compare. Can we not add isFlaky to that comparison path?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or a new FlutterGoldenFileComparator.compareFlaky method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah, sub-classes can add extra parameters. I'll give it a shot.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This turned out not so simple: #113396 (comment)

/// color. If the color is the same for all commits in the recent history, the
/// golden is likely no longer flaky and [isFlaky] can be set back to false. If
/// the color changes from commit to commit then it is still flaky.
AsyncMatcher matchesFlutterGolden(Object key, { int? version, bool isFlaky = false }) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a check in the analyzer that ensures every matchesGoldenFile has a Tag at the top of the test file. It should probably be updated to ensure uses of matchesFlutterGolden are accounted for.
Separately, we'd probably want to migrate all uses of matchesGoldenFile in the framework tests to use this one for consistency, and have the analyzer enforce it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the flutter/flutter wiki page on golden file testing for the framework will need to be updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. I'm going to add it to my TODO list, but will wait until we converge on the overall design before starting the migration. Also, I imagine migrating all tests should probably done incrementally, since there are many usages of matchesGoldenFile.


import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_goldens_client/skia_client.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:platform/platform.dart';
import 'package:test_api/src/expect/async_matcher.dart' show AsyncMatcher; // ignore: implementation_imports
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we be able to avoid this ignore if matchesGoldenFile was overridden instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

matchesGoldenFile is a top-level function. I can't think of a way to override it. Any ideas?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use the same name and hide it from the namespace? Not sure. If there is a way to not expose this and have this ignore that would be ideal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's exposed from package:flutter_test/flutter_test.dart. According to git grep there are 874 imports of flutter_test.dart. Does the benefit of hiding it outweigh the cost of the noise across the codebase?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dunno! Just brainstorming. I think in general there are a lot of options here. :)

final GoldenFileComparator nonFlakyComparator = await _createComparator();
_flakyGoldenFileComparator = await _createComparator(isFlaky: true);

// Assign this last because FlutterLocalFileComparator.fromDefaultComparator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I follow, is this a bug?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I admit, I don't understand the golden design well enough to tell. The problematic line is

defaultComparator ??= goldenFileComparator as LocalFileComparator;

So if I assign goldenFileComparator to anything other than LocalFileComparator the fromDefaultComparator fails the as cast, so I'm deferring the assignment till after all invocations of fromDefaultComparator.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this could be a lot simpler if the actual comparator doesn't have anything to do with flakiness

@@ -98,14 +98,14 @@ class TestGoldenComparator {
return _processManager!.start(command, environment: environment);
}

Future<String?> compareGoldens(Uri testUri, Uint8List bytes, Uri goldenKey, bool? updateGoldens) async {
Future<String?> compareGoldens(Uri testUri, Uint8List bytes, Uri goldenKey, bool? updateGoldens, Map<String, dynamic>? customProperties) async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is customProperties for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For any custom properties needed by the custom comparator supplied by flutter_test_config.dart. In the case of Flutter's own goldens the only custom property is isFlaky. Without it, I'd have to hard-code the notion of isFlaky into the tool. Since we decided to limit this concept to Flutter's own goldens, I had to add a more generic way of passing custom properties. I'm open to other suggestions.

Comment on lines 102 to 103
? await _flakyGoldenFileComparator.compare(bytes, goldenKey)
: await goldenFileComparator.compare(bytes, goldenKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, like right here.. instead of having separate comparators, why not just add compareFlaky as a method to the base abstract FlutterGoldenFileComparator class from flutter_goldens? The post-, pre-submit, and local comparators will be able to override it if they need to do anything special in each test environment.

It looks like it could eliminate a bunch of code creating and managing multiple comparators.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that compare is also called by the matcher, which knows nothing about flakiness. So even if I have compareFlaky or an override of compare with isFlaky parameter, the matcher will not specify it 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't you creating a custom matcher though? I may not be understanding this properly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still reusing the existing matchers. I just teach them to optionally take a custom comparator and use it instead of the default one.

I could make a custom copy of the matcher too. But now I'm starting to realize that by replacing matchesGoldenFile, the comparator, and the matcher, I'd pretty much be duplicating all existing functionality. Is that OK? Or should we look for a way to reuse and customize existing functionality? An idea:

  • Go back to Allow marking a golden check as flaky #111595, but instead of hard-coding isFlaky, we expose an optional named String? tag argument in matchesGoldenFile.
  • This argument would be passed to GoldenFileComparator unchanged.
  • We document that this argument is not used by the default implementation of the golden API but may be used in conjunction with flutter_test_config.dart to customize the functionality of custom comparators.

In the Flutter repo tag: 'flaky' would be implemented by the custom comparator to implement flaky goldens, e.g.:

matchesGoldenFile('date_picker_test.time.initial.png', tag: 'flaky')

Properties of this approach:

  • Pro: it does not hard-code the notion of "flaky" into the public golden API.
  • Pro: it reuses all of the existing golden functionality, so that customizations like this are easy to implement.
  • Pro: it's flexible enough for developer to customize for different things (it's just a string; you can put whatever you want in it).
  • Con: String-based API is not very strongly typed (can be alleviated by checking the value at runtime).
  • Con: it's breaking, but easily fixable (simply pass customProperties to flutter_test_config.dart, or ignore it if it's not needed).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But now I'm starting to realize that by replacing matchesGoldenFile, the comparator, and the matcher, I'd pretty much be duplicating all existing functionality.

I don't think you need to replace all of these things. We already have custom comparators. They do not need to be copied and rewritten. If we create a matchesFlutterGolden method for the specific purpose of the flutter framework, then it can call on the custom comparator (of type FlutterGoldenFileComparator) that we already have to execute the test however we want it to. Because it is already encapsulated for our own specific uses. I feel like a lot of this is not necessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #114026 as a rough example of what I mean.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you're right, I forgot that custom comparators can be reused, so we're not duplicating everything. Ok, moving in that direction.

'key': key,
'width': width.round(),
'height': height.round(),
'customProperties': <String, dynamic>{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then you may not need these customProperties, if it is just a method rather than a unique comparator that handles the flaky case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, the way web goldens work is the comparator running in the browser isn't comparing anything. It just sends a command to the Flutter Tool and the tool forwards it to a comparator process. The comparator process needs to know whether to compare the golden as stable or as flaky. I'm currently using the customProperties to attach the isFlaky flag. I couldn't think of a different approach.

@yjbanov yjbanov requested a review from Piinks October 25, 2022 00:47
@yjbanov yjbanov force-pushed the flaky-golden-api-2 branch from 6d75dee to 4cc45f9 Compare October 26, 2022 17:29
@yjbanov yjbanov force-pushed the flaky-golden-api-2 branch from 3e8b71b to e7e1d7e Compare October 27, 2022 02:08
@Piinks
Copy link
Contributor

Piinks commented Nov 1, 2022

I forked this so I could play with it and get a better understanding of the web implementation. #114450 I made a few tweaks, let me know what you think. :)

@yjbanov
Copy link
Contributor Author

yjbanov commented Nov 8, 2022

Closing in favor of #114450

@yjbanov yjbanov closed this Nov 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: tests "flutter test", flutter_test, or one of our tests a: text input Entering text in a text field or keyboard related problems c: contributor-productivity Team-specific productivity, code health, technical debt. d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels. tool Affects the "flutter" command-line tool. See also t: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Need a way to verify flaky golden test fixes
2 participants