• Home
Name Date Size #Lines LOC

..--

bin/12-May-2024-5,7544,791

images/12-May-2024-

lib/12-May-2024-4,5333,876

test/12-May-2024-603506

README.mdD12-May-20248.4 KiB240166

manifest.yamlD12-May-202420.5 KiB658514

pubspec.yamlD12-May-20245.6 KiB7766

README.md

1# Flutter devicelab
2
3"Devicelab" (a.k.a. "cocoon") is a physical lab that tests Flutter on real
4Android and iOS devices.
5
6This package contains the code for test framework and the tests. More generally
7the tests are referred to as "tasks" in the API, but since we primarily use it
8for testing, this document refers to them as "tests".
9
10Build results are available at https://flutter-dashboard.appspot.com.
11
12# Reading the dashboard
13
14## The build page
15
16The build page is accessible at https://flutter-dashboard.appspot.com/build.html.
17This page reports the health of build servers, called _agents_, and the statuses
18of build tasks.
19
20### Agents
21
22A green agent is considered healthy and ready to receive new tasks to build. A
23red agent is broken and does not receive new tasks.
24
25In the example below, the dashboard shows that the `linux2` agent is broken and
26requires attention. All other agents are healthy.
27
28![Agent statuses](images/agent-statuses.png)
29
30### Tasks
31
32The table below the agent statuses displays the statuses of build tasks. Task
33statuses are color-coded. The following statuses are available:
34
35**New task** (light blue): the task is waiting for an agent to pick it up and
36start the build.
37
38**Task is running** (spinning blue): an agent is currently building the task.
39
40**Task succeeded** (green): an agent reported a successful completion of the
41task.
42
43**Task is flaky** (yellow): the task was attempted multiple time, but only the
44latest attempt succeeded (we currently only try twice).
45
46**Task failed** (red): the task failed all of the attempts.
47
48**Task underperformed** (orange): currently not used.
49
50**Task was skipped** (transparent): the task is not scheduled for a build. This
51usually happens when a task is removed from `manifest.yaml` file.
52
53**Task status unknown** (purple): currently not used.
54
55In addition to color-coding, a task may display a question mark. This means
56that the task was marked as flaky manually. The status of such task is ignored
57when considering whether the build is broken or not. For example, if a flaky
58task fails, GitHub will not prevent PR submissions. However, if the latest
59status of a non-flaky task is red, all pending PRs will contain a warning about
60the broken build and recommend caution when submitting.
61
62Legend:
63
64![Task status legend](images/legend.png)
65
66The example below shows that commit `e122d5d` caused a wide-spread breakage,
67which was fixed by `bdc6f10`. It also shows that Cirrus and Chrome
68Infra (left-most tasks) decided to skip building these commits. Hovering over
69a cell will pop up a tooltip containing the name of the broken task. Clicking
70on the cell will open the log file in a new browser tab (only visible to core
71contributors as of today).
72
73![Broken Test](images/broken-test.png)
74
75## Why is a task stuck on "new task" status?
76
77The dashboard aggregates build results from multiple build environments,
78including Cirrus, Chrome Infra, and devicelab. While devicelab
79tests every commit that goes into the `master` branch, other environments
80may skip some commits. For example, Cirrus will only test the
81_last_ commit of a PR that's merged into the `master` branch. Chrome Infra may
82skip commits when they come in too fast.
83
84## How the devicelab runs the tasks
85
86The devicelab agents have a small script installed on them that continuously
87asks the CI server for tasks to run. When the server finds a suitable task for
88an agent it reserves that task for the agent. If the task succeeds, the agent
89reports the success to the server and the dashboard shows that task in green.
90If the task fails, the agent reports the failure to the server, the server
91increments the counter counting the number of attempts it took to run the task
92and puts the task back in the pool of available tasks. If a task does not
93succeed after a certain number of attempts (as of this writing the limit is 2),
94the task is marked as failed and is displayed using red color on the dashboard.
95
96# Running tests locally
97
98Do make sure your tests pass locally before deploying to the CI environment.
99Below is a handful of commands that run tests in a similar way to how the
100CI environment runs them. These commands are also useful when you need to
101reproduce a CI test failure locally.
102
103## Prerequisites
104
105You must set the `ANDROID_HOME` or `ANDROID_SDK_ROOT` environment variable to run
106tests on Android. If you have a local build of the Flutter engine, then you have
107a copy of the Android SDK at `.../engine/src/third_party/android_tools/sdk`.
108
109You can find where your Android SDK is using `flutter doctor`.
110
111## Warnings
112
113Running devicelab will do things to your environment.
114
115Notably, it will start and stop gradle, for instance.
116
117## Running all tests
118
119To run all tests defined in `manifest.yaml`, use option `-a` (`--all`):
120
121```sh
122../../bin/cache/dart-sdk/bin/dart bin/run.dart -a
123```
124
125## Running specific tests
126
127To run a test, use option `-t` (`--task`):
128
129```sh
130# from the .../flutter/dev/devicelab directory
131../../bin/cache/dart-sdk/bin/dart bin/run.dart -t {NAME_OR_PATH_OF_TEST}
132```
133
134Where `NAME_OR_PATH_OF_TEST` can be either of:
135
136- the _name_ of a task, which you can find in the `manifest.yaml` file in this
137  directory. Example: `complex_layout__start_up`.
138- the path to a Dart _file_ corresponding to a task, which resides in `bin/tasks`.
139  Tip: most shells support path auto-completion using the Tab key. Example:
140  `bin/tasks/complex_layout__start_up.dart`.
141
142To run multiple tests, repeat option `-t` (`--task`) multiple times:
143
144```sh
145../../bin/cache/dart-sdk/bin/dart bin/run.dart -t test1 -t test2 -t test3
146```
147
148To run tests from a specific stage, use option `-s` (`--stage`).
149Currently there are only three stages defined, `devicelab`,
150`devicelab_ios` and `devicelab_win`.
151
152
153```sh
154../../bin/cache/dart-sdk/bin/dart bin/run.dart -s {NAME_OF_STAGE}
155```
156
157## Running tests against a local engine build
158
159To run device lab tests against a local engine build, pass the appropriate
160flags to `bin/run.dart`:
161
162```sh
163../../bin/cache/dart-sdk/bin/dart bin/run.dart --task=[some_task] \
164  --local-engine-src-path=[path_to_local]/engine/src \
165  --local-engine=[local_engine_architecture]
166```
167
168An example of of a local engine architecture is `android_debug_unopt_x86`.
169
170# Reproducing broken builds locally
171
172To reproduce the breakage locally `git checkout` the corresponding Flutter
173revision. Note the name of the test that failed. In the example above the
174failing test is `flutter_gallery__transition_perf`. This name can be passed to
175the `run.dart` command. For example:
176
177```sh
178../../bin/cache/dart-sdk/bin/dart bin/run.dart -t flutter_gallery__transition_perf
179```
180
181# Writing tests
182
183A test is a simple Dart program that lives under `bin/tests` and uses
184`package:flutter_devicelab/framework/framework.dart` to define and run a _task_.
185
186Example:
187
188```dart
189import 'dart:async';
190
191import 'package:flutter_devicelab/framework/framework.dart';
192
193Future<void> main() async {
194  await task(() async {
195    ... do something interesting ...
196
197    // Aggregate results into a JSONable Map structure.
198    Map<String, dynamic> testResults = ...;
199
200    // Report success.
201    return new TaskResult.success(testResults);
202
203    // Or you can also report a failure.
204    return new TaskResult.failure('Something went wrong!');
205  });
206}
207```
208
209Only one `task` is permitted per program. However, that task can run any number
210of tests internally. A task has a name. It succeeds and fails independently of
211other tasks, and is reported to the dashboard independently of other tasks.
212
213A task runs in its own standalone Dart VM and reports results via Dart VM
214service protocol. This ensures that tasks do not interfere with each other and
215lets the CI system time out and clean up tasks that get stuck.
216
217# Adding tests to the CI environment
218
219The `manifest.yaml` file describes a subset of tests we run in the CI. To add
220your test edit `manifest.yaml` and add the following in the "tasks" dictionary:
221
222```
223  {NAME_OF_TEST}:
224    description: {DESCRIPTION}
225    stage: {STAGE}
226    required_agent_capabilities: {CAPABILITIES}
227```
228
229Where:
230
231 - `{NAME_OF_TEST}` is the name of your test that also matches the name of the
232 file in `bin/tests` without the `.dart` extension.
233 - `{DESCRIPTION}` is the plain English description of your test that helps
234 others understand what this test is testing.
235 - `{STAGE}` is `devicelab` if you want to run on Android, or `devicelab_ios` if
236 you want to run on iOS.
237 - `{CAPABILITIES}` is an array that lists the capabilities required of
238 the test agent (the computer that runs the test) to run your test. Available
239 capabilities are: `has-android-device`, `has-ios-device`.
240