Skip to content

[flutter_tools] Support Integration Tests #76200

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

Merged
merged 14 commits into from
Mar 31, 2021

Conversation

jiahaog
Copy link
Member

@jiahaog jiahaog commented Feb 17, 2021

Implements https://flutter.dev/go/tool-integration-test-support

Usage

Examples below are not exhaustive. Flags compatible with flutter test should work as well.

# Run an Integration Test.
flutter test integration_test/some_test.dart

# Run an Integration Test on the specified device.
flutter -d my-device-id test integration_test/some_test.dart

# Run all tests in `integration_test/` as Integration Tests.
flutter test integration_test

Minor changes:

  • Translate received test file paths to absolute paths before passing them to the package:test runner
  • Some tweaking of the FakeDevice to support mocking a LaunchResult

Upcoming PR

Related issue: #66264

@flutter-dashboard flutter-dashboard bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Feb 17, 2021
@google-cla google-cla bot added the cla: yes label Feb 17, 2021
@jiahaog jiahaog force-pushed the integration-test branch 2 times, most recently from 84eb4f9 to 68e8984 Compare February 24, 2021 01:15
@jiahaog jiahaog mentioned this pull request Feb 24, 2021
@jiahaog jiahaog force-pushed the integration-test branch 2 times, most recently from c565fdc to 29ecbd7 Compare February 24, 2021 08:24
Comment on lines +20 to +21
/// It is up to the device to determine if [entrypointPath] is a precompiled
/// or raw source file.
Copy link
Member Author

Choose a reason for hiding this comment

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

Unfortunately the abstraction here isn't very ideal.

For flutter_test, we can accept the precompiled dill, or if we move the compiler into FlutterTesterTestDevice, we can accept Dart source files.

For a raw Device, it accepts a source file, or a precompiled APK/IPA.

I can't quite think of a way to abstract this better given the awkward compilation of sources that happen in the FlutterTestPlatform for the flutter_tester. let me know if there's any better ideas.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think its OK, provided you document the convention.

@jiahaog
Copy link
Member Author

jiahaog commented Feb 24, 2021

@jonahwilliams Let me know if you have any early feedback for this - Most of the problems I've been having here have been resolved. (Still working on adding the tests)

@@ -23,7 +23,7 @@ import '../test/runner.dart';
import '../test/test_wrapper.dart';
import '../test/watcher.dart';

class TestCommand extends FlutterCommand {
class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider extending the description of the test command to describe the difference in behavior between test and integration test commands

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated the doc comment for this

/// [entrypointPath] must be a path to an uncompiled source file.
@override
Future<StreamChannel<String>> start(String entrypointPath) async {
final TargetPlatform targetPlatform = await device.targetPlatform;
Copy link
Contributor

Choose a reason for hiding this comment

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

Its worth thinking about how this implementation could be updated in the future to support testing without rebuilding the APK/IPA on each go. For example, by hot restarting the main isolate with the new entrypoint

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I think we could make flutter_platform.dart keep track of some sort of mutable state where rebuilding is skipped for subsequent workflows. For the first run we basically do what is here in this PR, and for subsequent runs we would invoke portions of the attach workflow, to attach and then hot restart the application. I can't be sure if it's sufficient without a prototype, but it seems like a reloadExistingApp boolean parameter here would be sufficient. It's also fine if we want to make breaking changes to the interface here because it's all internal anyway.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds reasonable to me

final vm_service.VmService vmService = await connectToVmService(launchResult.observatoryUri);

globals.printTrace('test $id: Finding the correct isolate with the integration test service extension');
final vm_service.IsolateRef isolateRef = await _findExtensionIsolate(vmService);
Copy link
Contributor

Choose a reason for hiding this comment

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

There may be some timing issues here, since the kIntegrationTestMethod will not be registered until after main finishes, but this may be after the app/isolate has started. There is a waitForExtension method in the resident_runner library that handles this cases, though it doesn't identify the correct Isolate:

Future<void> waitForExtension(vm_service.VmService vmService, String extension) async {

Copy link
Member Author

@jiahaog jiahaog Feb 25, 2021

Choose a reason for hiding this comment

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

Would there be issues with the implementation of _findExtensionIsolate method defined below? It's implementing something similar to the waitForExtension method (both subscribing to registered extension events as well as querying for current extensions, which should solve the timing issues here

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah that makes sense - I would prefer trying to reuse the existing helper if possible.

Copy link
Member Author

Choose a reason for hiding this comment

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

Refactoring to make the existing helper reusable here was done in #77220, and just updated this PR to use the helper here.

Comment on lines +20 to +21
/// It is up to the device to determine if [entrypointPath] is a precompiled
/// or raw source file.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think its OK, provided you document the convention.

@jiahaog jiahaog marked this pull request as ready for review March 29, 2021 14:12
@flutter-dashboard flutter-dashboard bot added the c: contributor-productivity Team-specific productivity, code health, technical debt. label Mar 29, 2021
@jiahaog
Copy link
Member Author

jiahaog commented Mar 29, 2021

Sorry for the delay, I was caught up with some other things, and just found some time to clean this PR up and add more tests. It is finally ready for review 🙂

(I also have a follow up PR #79258 to add device lab tests)

@jiahaog jiahaog requested a review from jonahwilliams March 29, 2021 14:28
Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

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

Overall this LGTM.

How comfortable do you feel with these changes, do you think we should wait until the next release cut, or until the devicelab test is ready?

As long as the existing flutter test behavior` is unchanged it should be OK

jiahaog added 2 commits March 30, 2021 10:03
Canonical paths become lowercased on Windows. This causes less
information to be returned from the VM after adding a breakpoint
(observe that the UnresolvedSourceLocation does not have a `script`
below:

bad (at previous commit)

```
{"jsonrpc":"2.0","method":"streamNotify","params":{"streamId":"Debug","event":{"type":"Event","kind":"BreakpointAdded","isolate":{"type":"@isolate","id":"isolates/2153249320239607","name":"main","number":"2153249320239607","isSystemIsolate":false},"timestamp":1617078845364,"breakpoint":{"type":"Breakpoint","fixedId":true,"id":"breakpoints/1","breakpointNumber":1,"resolved":false,"location":{"type":"UnresolvedSourceLocation","scriptUri":"file:///C:/Users/Jia%20Hao/AppData/Local/Temp/flutter_test_expression_eval_test.c001d9de/test/test.dart","line":5}}}}}
```

good (at HEAD)

```
{"jsonrpc":"2.0","method":"streamNotify","params":{"streamId":"Debug","event":{"type":"Event","kind":"BreakpointAdded","isolate":{"type":"@isolate","id":"isolates/2029881360067999","name":"main","number":"2029881360067999","isSystemIsolate":false},"timestamp":1617079201477,"breakpoint":{"type":"Breakpoint","fixedId":true,"id":"breakpoints/1","breakpointNumber":1,"resolved":false,"location":{"type":"UnresolvedSourceLocation","script":{"type":"@script","fixedId":true,"id":"libraries/@22372424/scripts/file%3A%2F%2F%2FC%3A%2FUsers%2FJia%2520Hao%2FAppData%2FLocal%2FTemp%2Fflutter_test_expression_eval_test.17a2bb2c%2Ftest%2Ftest.dart/178816e6d05","uri":"file:///C:/Users/Jia%20Hao/AppData/Local/Temp/flutter_test_expression_eval_test.17a2bb2c/test/test.dart","_kind":"kernel"},"line":5}}}}}
```

This makes the test [1] confused as it keeps waiting forever.

[1]: https://github.com/flutter/flutter/blob/e43738824e88827984bbd7a85fdb11e0ef5398c9/packages/flutter_tools/test/integration.shard/expression_evaluation_test.dart#L113
@jiahaog
Copy link
Member Author

jiahaog commented Mar 30, 2021

I think it should be fine to land this without waiting for the next release cut. The only change to the normal flutter test flow is the change to use canonical paths which didn't work on windows when debugging, so I've just updated the PR to use absolute paths. Also just manually tested adding a breakpoint and expression evaluation of the widget test flow on macOS, Linux and Windows in VSCode, and it seems to work fine. Is there anything else I should test manually?

Also, I figured out how to test the device lab changes locally in #79258 (found an issue and updated this PR to disable port publication like how drive does it), and we should be good to land the device lab change right after this PR lands. Splitting it off into its own PR so that would be easier to revert, as I'm a bit unsure of whether dev/prod_builders.json is specified correctly there.

@DanTup
Copy link
Contributor

DanTup commented Mar 30, 2021

FWIW, I have an open PR in Dart-Code to support this. I don't plan to merge it for the upcoming release (this week) as I wanted to re-test it all once this PR is complete/merged (it also needs some automated tests). I'll likely merge it just after my release though (and I can make a preview build of the extension that includes the changes for testing/using in the meantime).

Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

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

only have a nit.

LGTM

Co-authored-by: Jonah Williams <jonahwilliams@google.com>
@jiahaog
Copy link
Member Author

jiahaog commented Mar 31, 2021

@DanTup sure, no hurry. I'll merge this and then try and patch your change as well to test it out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: contributor-productivity Team-specific productivity, code health, technical debt. tool Affects the "flutter" command-line tool. See also t: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants