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

Conversation

@matanlurey
Copy link
Contributor

@matanlurey matanlurey commented Sep 27, 2024

Closes flutter/flutter#155769.

This is a variant of the approach in #52241, based on feedback from @jakemac53 and @jonahwilliams (who originally sped up dart test significantly by using frontend_server under the scenes: dart-lang/test#1399), in short:

# tools/engine_tool/BUILD.gn

import("//flutter/build/dart/internal/gen_dartcli_call.gni")

gen_dartcli_call("tests") {
  args = [ "test" ]
  cwd = "//flutter/tools/engine_tool"
}

This stanza, when built (ninja -C ../out/host_debug flutter/tools/engine_tool:tests) generates the following file:

# ../out/host_debug/gen/flutter/tools/engine_tool/tests

set -e

# Needed because if it is set, cd may print the path it changed to.
unset CDPATH

# Store the current working directory.
prev_cwd=$(pwd)

# Set a trap to restore the working directory.
trap 'cd "$prev_cwd"' EXIT

CD_PATH="/Users/matanl/Developer/engine/src/flutter/tools/engine_tool"
if [ -n "$CD_PATH" ]; then
  cd "$CD_PATH"
fi

/Users/matanl/Developer/engine/src/flutter/prebuilts/macos-arm64/dart-sdk/bin/dart "test"

In turn, when executed (../out/host_debug/gen/flutter/tools/engine_tool/tests) it just runs dart test:

flutter % ../out/host_debug/gen/flutter/tools/engine_tool/tests
Building package executable... 
Built test:test.
00:00 +0: test/test_command_test.dart: test command executes test                                                                                                                                                                                                          
00:00 +3: test/run_command_test.dart: run command invokes flutter run
...
00:00 +117: All tests passed!

There is no actual compilation performed by the tool (that is handled implicitly by dart test), and as a result neither a depfile is needed, nor generating a pre-compiled artifact like a snapshot or AOT elf/assembly.


This work is incomplete, that is, we'd want to properly tag the executable so et can find it, and create a wrapper template (i.e. dart_test) that tightens things up a bit, but I wanted to show the work at this intermediate step to get feedback before moving forward.

/cc @jonahwilliams, @jtmcdole as well.

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!).

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

script = string.Template(
'''#!/bin/sh

set -e
Copy link
Contributor

Choose a reason for hiding this comment

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

dumb question because I get tripped up on this constantly. set -e makes sure that the exit code of this script is non zero if the dart test exit code is non zero right? Can you check that failed tests report non-zero exit codes through the shell script too?

Copy link
Member

@jtmcdole jtmcdole Sep 27, 2024

Choose a reason for hiding this comment

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

Any command or pipeline that has an error will exit the script automatically. Dart tests that fail set errno 1.

parser.add_argument('--output', required=True, help='Output file')
parser.add_argument('--command', required=True, help='Command to run')
parser.add_argument('--cwd', required=False, help='Working directory')
parser.add_argument('rest', nargs='*', help='Arguments to pass to the command')
Copy link
Member

Choose a reason for hiding this comment

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

I <3 rest vs args +1

@zanderso
Copy link
Member

Does dart test do an implicit pub get?

@matanlurey
Copy link
Contributor Author

Does dart test do an implicit pub get?

Yes, I believe it does. My thought that given how workspaces work, it shouldn't matter though?

(Side-note, if it does matter, we should make sure to change run_tests.py in the meantime).

@jakemac53
Copy link
Contributor

Yes, I believe it does. My thought that given how workspaces work, it shouldn't matter though?

Right, it shouldn't matter, but if we really wanted to skip it there might be a flag for that... cc @bkonyi .

@bkonyi
Copy link
Contributor

bkonyi commented Sep 27, 2024

Yes, I believe it does. My thought that given how workspaces work, it shouldn't matter though?

Right, it shouldn't matter, but if we really wanted to skip it there might be a flag for that... cc @bkonyi .

I don't think there's a flag to disable the automatic pub get since dart test triggers some precompilation steps before running tests. The argument handling for dart test is all from package:test and the precompilation logic is built into package:pub, so we'd need to add some logic there to support this (assuming we can).

@jakemac53
Copy link
Contributor

I don't think there's a flag to disable the automatic pub get since dart test triggers some precompilation steps before running tests.

As in the precompilation of the test package itself? If pub still has a run command, you should be able to just do pub run instead of pub get (it will also trigger the precompilation).

@bkonyi
Copy link
Contributor

bkonyi commented Sep 27, 2024

I don't think there's a flag to disable the automatic pub get since dart test triggers some precompilation steps before running tests.

As in the precompilation of the test package itself? If pub still has a run command, you should be able to just do pub run instead of pub get (it will also trigger the precompilation).

Yes, precompilation of the test package. dart test doesn't call pub run or pub get directly, it simply calls getExecutableForCommand('test:test') and passes the returned executable path back for the VM to run.

@jakemac53
Copy link
Contributor

Yes, precompilation of the test package. dart test doesn't call pub run or pub get directly, it simply calls getExecutableForCommand('test:test') and passes the returned executable path back for the VM to run.

It looks like that calls ensureUpToDate - which only does a pub get if necessary, which is probably a good thing in this case?

@bkonyi
Copy link
Contributor

bkonyi commented Sep 27, 2024

Yes, precompilation of the test package. dart test doesn't call pub run or pub get directly, it simply calls getExecutableForCommand('test:test') and passes the returned executable path back for the VM to run.

It looks like that calls ensureUpToDate - which only does a pub get if necessary, which is probably a good thing in this case?

Do we want to be running pub get at all on test infrastructure or are we relying on a custom package config to reference third_party/ dependencies and other local packages like we do in the SDK?

@jakemac53
Copy link
Contributor

jakemac53 commented Sep 27, 2024

Do we want to be running pub get at all on test infrastructure or are we relying on a custom package config to reference third_party/ dependencies and other local packages like we do in the SDK?

The engine (at least for the most part) uses pub workspaces, with overrides for the third party deps (pulled in via a DEPS file IIRC). https://github.com/flutter/engine/blob/main/pubspec.yaml. This means pub get is safe to do.

I would love the Dart SDK to also do it this way :).

Copy link
Member

@jtmcdole jtmcdole left a comment

Choose a reason for hiding this comment

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

LGTM

unset CDPATH

# Store the current working directory.
prev_cwd=$$(pwd)
Copy link
Member

@cbracken cbracken Sep 27, 2024

Choose a reason for hiding this comment

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

Could save yourself a variable with pushd "$CD_PATH" > /dev/null and popd > /dev/null in the exit signal handler. Also wouldn't need to worry about CDPATH above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, that's much simpler!

Added a PWD "test" as well.

Copy link
Member

@cbracken cbracken left a comment

Choose a reason for hiding this comment

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

LGTM stamp from a Japanese personal seal

@matanlurey
Copy link
Contributor Author

I think @zanderso wanted a chance to weigh in here, and is OOO, so I'll check back with Monday before merging.

@zanderso
Copy link
Member

Sorry, a couple more questions.

Is there any way to make the implied pub get run in --offline mode the same way that we do when setting up the tree in tools/pub_get_offline.py? I think this is not critical since the workspace should already be set up after a gclient sync, but I know folks forget to run gclient sync after doing a git pull all the time, and I'd like to avoid folks (and CI) getting their tree into a weird state.

Does dart test write to the source tree at all? If so, any files it writes will have to be cleaned up after the tests run, or we'll have to find somewhere else for it to write the files. For example, does it write any intermediate compilation artifacts anywhere? If it needs to do that, we'll have to find some way to avoid those being written in the source tree, or clean them up afterwords. Stray files in the source tree risk confusing the caching of the source tree that CI does.

@matanlurey
Copy link
Contributor Author

Is there any way to make the implied pub get run in --offline mode the same way that we do when setting up the tree in tools/pub_get_offline.py? I think this is not critical since the workspace should already be set up after a gclient sync, but I know folks forget to run gclient sync after doing a git pull all the time, and I'd like to avoid folks (and CI) getting their tree into a weird state.

No, there is not. We could definitely request one if we end up thinking its important.

But, on the importance, I'm struggling a bit to understand what we're trying to avoid:

  • With workspace (and the enforcement of pub_get_offline.py) I'm not sure what it could do?
  • We already are using dart test, both locally and on CI.

Does dart test write to the source tree at all?

It does place files in .dart_tool/test:

Screenshot 2024-09-28 at 6 47 10 PM

But I'm guessing since it's in .gitignore we aren't considering that the source tree?

@zanderso
Copy link
Member

  • With workspace (and the enforcement of pub_get_offline.py) I'm not sure what it could do?

If someone does a git pull without doing a gclient sync, then pub_get_offline.py won't have run. So my question is more, what is the failure mode if someone does git pull and then immediately dart test in a situation where the git pull updated the pubspec.yaml. Will it be easy to debug? Would an --offline flag to dart test make the failure more obvious? To be clear these questions are not intended to block this PR, but they are things we should be thinking about.

It does place files in .dart_tool/test:
But I'm guessing since it's in .gitignore we aren't considering that the source tree?

CI does filesystem level caching, so even files that are .gitignored in the source tree may persist between CI runs. Do we understand what the behavior of dart test is w.r.t. the files under .dart_tool/test when e.g. the version of package:test or the Dart SDK is updated?

Also a couple of questions for @bkonyi:

  1. Does dart test send telemetry? Should we be explicitly disabling that on CI, somehow? Does dart test take a --disable-telemetry flag?
  2. My understanding is that at some point in the near future, the Dart CLI will spawn a persistent compilation daemon. That means that these dart test invocation will spawn that process. Especially on CI, how will we be able to ensure that the daemons are killed between runs?

@jtmcdole
Copy link
Member

CI does filesystem level caching, so even files that are .gitignored in the source tree may persist between CI runs

That's a surprising tidbit - is it documented somewhere? I would have imagined block level caching.

@bkonyi
Copy link
Contributor

bkonyi commented Sep 30, 2024

Also a couple of questions for @bkonyi:

  1. Does dart test send telemetry? Should we be explicitly disabling that on CI, somehow? Does dart test take a --disable-telemetry flag?

The Dart CLI has a top-level --suppress-analytics flag that could be provided (e.g., dart --suppress-analytics test), but package:unified_analytics should be smart enough to detect if we're running on CI and disable telemetry automatically (detection logic found here).

  1. My understanding is that at some point in the near future, the Dart CLI will spawn a persistent compilation daemon. That means that these dart test invocation will spawn that process. Especially on CI, how will we be able to ensure that the daemons are killed between runs?

@derekxu16 will know more about this since he's been the one working on it.

Would we want to keep the compilation server running and shared between tests on a shard? If not, there should be a way for the compilation server to have the same lifespan as the test process. If we do want to shared the compilation server, it should be as simple as adding a step to run dart compilation-server shutdown after all the tests have finished running.

@jakemac53
Copy link
Contributor

Do we understand what the behavior of dart test is w.r.t. the files under .dart_tool/test when e.g. the version of package:test or the Dart SDK is updated?

It is using the frontend server and passing a previous dill file to it to initialize from. The frontend server handles invalidating that as needed afaik (but if it doesn't do that, we have larger problems).

@zanderso
Copy link
Member

CI does filesystem level caching, so even files that are .gitignored in the source tree may persist between CI runs

That's a surprising tidbit - is it documented somewhere? I would have imagined block level caching.

The recipes use https://flutter.googlesource.com/recipes/+/refs/heads/main/recipe_modules/cache/api.py, which reads/writes files to the CAS service.

@johnmccutchan
Copy link
Contributor

Also a couple of questions for @bkonyi:

  1. Does dart test send telemetry? Should we be explicitly disabling that on CI, somehow? Does dart test take a --disable-telemetry flag?

The Dart CLI has a top-level --suppress-analytics flag that could be provided (e.g., dart --suppress-analytics test), but package:unified_analytics should be smart enough to detect if we're running on CI and disable telemetry automatically (detection logic found here).

  1. My understanding is that at some point in the near future, the Dart CLI will spawn a persistent compilation daemon. That means that these dart test invocation will spawn that process. Especially on CI, how will we be able to ensure that the daemons are killed between runs?

@derekxu16 will know more about this since he's been the one working on it.

Would we want to keep the compilation server running and shared between tests on a shard? If not, there should be a way for the compilation server to have the same lifespan as the test process. If we do want to shared the compilation server, it should be as simple as adding a step to run dart compilation-server shutdown after all the tests have finished running.

I think we need to be more careful than just shutting it down. We need these test runs to be hermetic. So, we can't have one test using a different tests' compilation server.

Is it possible to ensure that no other process connects to a compilation server?

@derekxu16
Copy link
Contributor

Is it possible to ensure that no other process connects to a compilation server?

Compilation servers will be associated with "info files", so it will be possible to specify which compilation server an invocation of dart test will connect to with the --resident-compiler-info-file CLI option. So passing a unique --resident-compiler-info-file argument to each invocation of dart test will result in those invocations being hermetic.

@matanlurey
Copy link
Contributor Author

Let's wrap up the discussion on this PR about possible semantics of tools.

I opened 2 more issues to encourage discussion elsewhere:

  • Dirtying the source tree semantics #155949
  • dart test semantics on engine CI #155950

@matanlurey
Copy link
Contributor Author

@johnmccutchan or @zanderso Do either of you have feedback specifically about this PR (i.e. should block merging)? If not, I plan to merge this shortly.

@zanderso
Copy link
Member

@matanlurey LGTM w/ --suppress-analytics passed to dart test.

@derekxu16 @bkonyi Please keep the engine team and @johnmccutchan in the loop w.r.t. the persistent compilation daemon on CI.

@matanlurey matanlurey added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 30, 2024
@auto-submit auto-submit bot merged commit f5abfa0 into flutter:main Sep 30, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 30, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 30, 2024
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Oct 1, 2024
…155967)

flutter/engine@e61bc85...bfb6ddd

2024-09-30 [email protected] Roll Skia from 534633fb4bd9 to d1d7deb68f9d (1 revision) (flutter/engine#55534)
2024-09-30 [email protected] Roll Dart SDK from 79863e31de87 to d9fb41a4b5ee (1 revision) (flutter/engine#55533)
2024-09-30 [email protected] Introduce a GN rule that (explicitly) generates a `dart test` wrapper (flutter/engine#55475)
2024-09-30 [email protected] Remove the need to use `runZoned` by replacing `print` statements (flutter/engine#55530)
2024-09-30 [email protected] Roll Skia from 6c89706638ee to 534633fb4bd9 (2 revisions) (flutter/engine#55531)
2024-09-30 [email protected] [Impeller] Create a libImpeller dylib and expose symbols. (flutter/engine#55526)
2024-09-30 [email protected] Added metal validation for `impeller_unittests (flutter/engine#55527)
2024-09-30 [email protected] Roll Skia from dfeeb199b226 to 6c89706638ee (2 revisions) (flutter/engine#55528)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
thejitenpatel pushed a commit to thejitenpatel/flutter that referenced this pull request Oct 1, 2024
…lutter#155967)

flutter/engine@e61bc85...bfb6ddd

2024-09-30 [email protected] Roll Skia from 534633fb4bd9 to d1d7deb68f9d (1 revision) (flutter/engine#55534)
2024-09-30 [email protected] Roll Dart SDK from 79863e31de87 to d9fb41a4b5ee (1 revision) (flutter/engine#55533)
2024-09-30 [email protected] Introduce a GN rule that (explicitly) generates a `dart test` wrapper (flutter/engine#55475)
2024-09-30 [email protected] Remove the need to use `runZoned` by replacing `print` statements (flutter/engine#55530)
2024-09-30 [email protected] Roll Skia from 6c89706638ee to 534633fb4bd9 (2 revisions) (flutter/engine#55531)
2024-09-30 [email protected] [Impeller] Create a libImpeller dylib and expose symbols. (flutter/engine#55526)
2024-09-30 [email protected] Added metal validation for `impeller_unittests (flutter/engine#55527)
2024-09-30 [email protected] Roll Skia from dfeeb199b226 to 6c89706638ee (2 revisions) (flutter/engine#55528)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
aam added a commit to aam/engine that referenced this pull request Oct 1, 2024
aam added a commit that referenced this pull request Oct 1, 2024
Follow-up to #55475

Test: `flutter/tools/gn --no-prebuilt-dart-sdk --unoptimized
--runtime-mode debug && ninja -C out/host_debug_unopt`
fluttermirroringbot pushed a commit to flutter/flutter that referenced this pull request Dec 18, 2024
Follow-up to flutter/engine#55475

Test: `flutter/tools/gn --no-prebuilt-dart-sdk --unoptimized
--runtime-mode debug && ninja -C out/host_debug_unopt`
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

autosubmit Merge PR when tree becomes green via auto submit App

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add foundational bits to enable dart_test-type rules in the engine

9 participants