Running and writing "Tast" automated end to end (E2E) tests
Note
This page's primary audience is for Googlers, since Tast E2E automation is a common requirement of ChromeOS feature development.
Prerequisites
Checkout and set up ChromeOS repo.
If you only work on Chromium and haven’t checked out the ChromiumOS repo, do so now with instructions at Getting Started.
If you already have ChromeOS set up but haven't touched it in a while, it's
probably a good idea to run repo sync
and run cros build-packages --board=${BOARD}
; the latter will also call update_chroot
for you.
Set up DUT with correct version of Chrome and ChromeOS
If you are writing integration tests for a new or relatively new feature, make sure your test device has the binary with that feature included.
For new Chrome or ChromeOS features, follow instructions at Getting Started.
Running Tast tests
Running a Tast test is pretty simple. From your workstation (desktop or
cloudtop), navigate to ChromiumOS repo and start cros_sdk
. From within your
shell, run:
(cr)$ tast --verbose run ${DUT} ${TEST_NAME}
This will build, deploy, and run the specified integration test on your DUT.
Tip: The name of a test follows the format of <GO PACKAGE>.<TEST NAME>.<PARAMETER SUFFIX>
. The .<PARAMETER SUFFIX>
suffix is only applicable
for
parameterized tests.
If a test requires a parameter suffix but it's not provided, the test will not
be found. Additionally, you can use the wildcard operator to specify multiple
tests, e.g. bluetooth.*
.
DUT is short for Device Under Test. Replace ${DUT} with the ip address where your DUT can be reached. ex) localhost:7777. Test name is the test that you want to run. It is the combination of package name and function name. For example, the test name for the test in this file is “diagnostics.LaunchDiagnosticsFromLauncher”.
Shortly after executing the command, Tast should remotely control your test device to run the integration test. Your device under test for "diagnostics.LaunchDiagnosticsFromLauncher" should look like this.
Running a test multiple times
Running a Tast test multiple times can be helpful when trying to debug flaky
failures, or to provide more confidence that your test/changes aren't flaky
themselves. While this would be painful to do with tast run ...
, we luckily
have a script accessible to us called repeat-test.sh
that allows us to run a
test an arbitrary number of times using the -r #
argument. For example,
executing the following command in your shell will run the
policy.AllowDinosaurEasterEggEnrolled
test 25
times:
(cr)$ ~/chromiumos/src/platform/tast-tests/tools/repeat-test.sh \
-r 25 -- 127.0.0.1:2200 policy.AllowDinosaurEasterEggEnrolled
Cross-device tests
Cross-device tests require some additional setup. Make sure that your DUT has a "Test" build from go/goldeneye, and follow the instructions in go/run-nearby-tast-tests and go/multi-dut-android-setup to set up your phone. The phone will need to be connected to the DUT over USB.
Cleanup after cross-device tests
If you would like to remove an owner account from your devices added during a test, run this command from the VT2 terminal:
$ crossystem clear_tpm_owner_request=1
Then, reboot:
$ reboot
Writing Tast tests
Refer to go/tast-writing for generic information on writing Tast tests.
Tast code is located in the tast-tests git repo. Navigate to
~/trunk/src/platform/tast-tests
inside the chroot or
~/chromiumos/src/platform/tast-tests
outside the chroot. Be sure to run any
git commands inside or below this directory.
To add a new test, create a new file in the test directory under the appropriate package. Under the init() function fill out the description of the test, and add yourself to the contact information array.
As described in go/tast-writing, be sure to add "group:mainline" and “informational” string to the attribute array as well. Informational attribute marks the integration test non-blocking. It’s standard practice to let your integration test run without a flake for 20 consecutive runs, after which you can remove the informational attribute tag to promote the test to blocking. You can monitor flakey-ness of your test at tastboard.
Other useful documentation worth reviewing include:
- go/tast-test-intro
Parameterized Tests
If you need to run multiple Tast tests from a single file, but change specific variables or metadata/fixture setup between runs, you can parameterize the test. There are two different methods of parameterization: table-driven tests, and test parameters.
-
Table-Driven Tests
If you need to test multiple scenarios with very slight differences, you should use a table-driven test. Table driven tests are the most common pattern.
for _, tc := range []struct { format string filename string duration time.Duration }{ { format: "VP8", filename: "sample.vp8", duration: 3 * time.Second, }, { format: "VP9", filename: "sample.vp9", duration: 3 * time.Second, }, { format: "H.264", filename: "sample.h264", duration: 5 * time.Second, }, } { s.Run(ctx, tc.format, func(ctx context.Context, s *testing.State) { if err := testPlayback(ctx, tc.filename, tc.duration); err != nil { s.Error("Playback test failed: ", err) } }) }
Read more about table-driven tests in the table-driven test documentation.
-
Test Parameters
Table-driven tests are almost always preferred, unless...
-
Tests should have different attributes: only some tests need an extra attribute, which cannot be facilitated with table-driven tests, as all fields must be defined.
-
Tests should declare different dependencies.
-
Test results should be reported separately: defining tests as parameters reports metrics separately. In which case, adding new test parameters may be preferable.
Add
Params
in the configParams: []testing.Param{ { Name: "vp8", Val: "sample.vp8", ExtraData: []string{"sample.vp8"}, ExtraAttr: []string{"informational"}, } { Name: "vp9", Val: "sample.vp9", ExtraData: []string{"sample.vp9"}, // ExtraAttr is excluded here. } { Name: "h264", Val: "sample.h264", ExtraSoftwareDeps: []string{"chrome_internal"}, // H.264 codec is unavailable on ChromiumOS ExtraData: []string{"sample.h264"}, // Additional data is included here. ExtraAttr: []string{"informational"}, }},
Val
is an arbitrary value that can be accessed in the test body viastate.Parameter.Param
. It must be type-asserted immediately. For example:filename := state.Param().(string)
Extra*
, likeExtraAttr
, can also be accessed viatesting.Param
. Read about the customizable properties oftesting.Param
here.TIP: Read more about test parameters in the parameterized test documentation.
-
Adding a Lacros test
Lacros is an ongoing effort to separate the Chrome browser from the system UI in ChromeOS. This may require an additional test variant to ensure functionality works as expected when Lacros is enabled. We can paramatize existing tests to add a Lacros variant.
-
Enable Lacros through a variant:
import ( "chromiumos/tast/local/chrome/browser" "chromiumos/tast/local/chrome/browser/browserfixt" ) Params: []testing.Param{ { Val: browser.TypeAsh, Fixture: "chromeLoggedIn", } { Name: "lacros", Val: browser.TypeLacros, Fixture: "lacros", ExtraSoftwareDeps: []string{"lacros"}, }}
-
Setup and open the browser
If your test requires the use of the Chrome browser, Lacros enabled variants of the test should open an instance of Chrome before attempting to interact with the browser.
br, closeBrowser, err := browserfixt.SetUp(ctx, s.FixtValue().(chrome.HasChrome).Chrome(), s.Param().(browser.Type)) if err != nil { s.Fatal("Failed to set up browser: ", err) } defer closeBrowser(cleanupCtx)
TIP: Read more about Lacros tast test porting at go/lacros-tast-porting.
Tips for working with CLs in ChromiumOS
-
Every commit is a CL
Unlike in Chromium where a CL is represented by a branch, each commit will be treated as a CL when you upload usingrepo upload
. -
Change-Ids are generated when you run
git commit
Unlike in Chromium where the Change-Id is added to the commit message when you upload the CL, in ChromiumOS the Change-Id is generated locally by a git hook when you commit. Take care not to delete the Change-Id!If you need to reupload the CL to make changes, then you have to update the original commit using
git commit --amend
or by usinggit rebase -i
, etc. So long as the Change-Id of the original commit remains intact, it will be associated with the correct review in Gerrit. -
Avoid editing your commit messages in Gerrit
Whenever you upload your changes, your local commit message will overwrite what's in Gerrit, so it's probably best to avoid editing your commit messages in Gerrit altogether. Instead, usegit commit --amend
to update the commit message and upload the CL again. -
Commit messages have to be formatted differently
[SmartLock] Adapt tests to use revamp feature The new Smart Lock UI introduced by the SmartLockUIRevamp flag doesn't quite work with the existing Tast tests. Update the tests to correctly select the new UI elements, and enable the flag in the test fixtures. BUG=b:223435238 TEST=tast run 'smartlock.*' Change-Id: I8fb62aecbd880476065bf61c3d4002e6a96a5290
- The Change-Id has to be in a paragraph of its own at the end.
- BUG (or FIXED) and TEST must be included in the previous paragraph, and must use the = syntax. Buganizer bugs have to use the : syntax.
-
"Verified" has to have +1 before the CL can be submitted
You're allowed to set Verified +1 if you've verified the change. Reviewers generally treat Verified +1 as a signal that the change is ready for review. {style="display:block;margin:auto;width:800px"}
Links
- Setting up ChromiumOS: go/chromeos-building
- Extra info on submitting CLs to ChromiumOS: go/cros-contributing
- Getting cross-device tests running:
- go/run-nearby-tast-tests
- go/multi-dut-android-setup
- Cheatsheet for Cellular tests: go/cellular-ui-tast-cheatsheet
- Tast reference:
- go/tast-test-intro
- go/tast-quickstart
- go/tast-running
- go/tast-writing
- go/tast-overview
- go/cros-connectivity-servo