michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 1 | # Continuous build and test infrastructure for Chromium for iOS |
| 2 | |
| 3 | See the [instructions] for how to check out and build Chromium for iOS. |
| 4 | |
| 5 | The Chromium projects use buildbot for continuous integration. This doc starts |
| 6 | with an overview of the system, then gives detailed explanations about each |
| 7 | part. |
| 8 | |
| 9 | [TOC] |
| 10 | |
| 11 | ## Overview |
| 12 | |
| 13 | Commits are made using the [commit queue], which triggers a series of try jobs |
| 14 | to compile and test the proposed patch against Chromium tip of tree before |
| 15 | actually making the commit. If the try jobs succeed the patch is committed. A |
| 16 | newly committed change triggers the builders (or "bots") to compile and test |
| 17 | the change again. |
| 18 | |
| 19 | ## Bots |
| 20 | |
| 21 | Bots are slaves attached to a buildbot master (or "waterfall"). A buildbot |
| 22 | master is a server which polls for commits to a repository and triggers workers |
| 23 | to compile and test new commits whenever they are detected. [chromium.mac] is |
| 24 | the main waterfall for Mac desktop and iOS. [tryserver.chromium.mac] serves |
| 25 | as the try server for Mac desktop and iOS. |
| 26 | |
| 27 | The bots know how to check out a given revision of Chromium, compile, and test. |
| 28 | |
| 29 | ### Code location |
| 30 | |
| 31 | #### Master configs |
| 32 | |
| 33 | The masters are configured in [tools/build], a separate repository which |
| 34 | contains various infra-related scripts. |
| 35 | |
| 36 | #### Pollers |
| 37 | |
| 38 | [chromium.mac] uses a `GitilesPoller` which polls the Chromium repository for |
| 39 | new commits using the [gitiles] interface. When a new commit is detected, the |
| 40 | bots are triggered. |
| 41 | |
| 42 | #### Recipes |
| 43 | |
| 44 | The bots run [recipes], which are scripts that specify their sequence of steps |
| 45 | located in [tools/build]. An iOS-specific [recipe module] contains common |
| 46 | functionality that the various [iOS recipes] use. |
| 47 | |
| 48 | #### Configs |
| 49 | |
| 50 | Because the recipes live in another repository, changes to the recipes don't |
| 51 | go through the Chromium [commit queue] and aren't tested on the [try server]. |
| 52 | In order to allow bot changes to be tested by the commit queue, the recipes |
| 53 | for iOS are generic instead of bot-specific, and rely on configuration files |
| 54 | which live in master-specific JSON config files located in [src/ios/build/bots]. |
| 55 | These configs define the `gn_args` to use during compilation as well as the |
| 56 | tests to run. |
| 57 | |
| 58 | #### Scripts |
| 59 | |
| 60 | The [test runner] is the script which installs and runs the tests, interprets |
| 61 | the results, and collects any files emitted by the test ("test data"). It can |
| 62 | be found in [src/ios/build/bots/scripts], which means changes to the test runner |
| 63 | can be tested on the [try server]. |
| 64 | |
Takuto Ikuta | 7478af72 | 2024-05-27 07:23:19 | [diff] [blame] | 65 | ### Compiling with reclient |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 66 | |
Takuto Ikuta | 7478af72 | 2024-05-27 07:23:19 | [diff] [blame] | 67 | Reclient is the distributed build system used by Chromium. It reduces |
| 68 | compilation time by avoiding recompilation of objects which have already been |
| 69 | compiled elsewhere. |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 70 | |
| 71 | ### Testing with swarming |
| 72 | |
| 73 | Tests run on [swarming], a distributed test system used by Chromium. After |
| 74 | compilation, configured tests will be zipped up along with their necessary |
| 75 | dependencies ("isolated") and sent to the [swarming server] for execution. The |
| 76 | server issues tasks to its attached workers for execution. The bots themselves |
| 77 | don't run any tests, they trigger tests to be run remotely on the swarming |
| 78 | server, then wait and display the results. This allows multiple tests to be |
| 79 | executed in parallel. |
| 80 | |
| 81 | ## Try bots |
| 82 | |
| 83 | Try bots are bots which test proposed patches which are not yet committed. |
| 84 | |
| 85 | Request [try job access] in order to trigger try jobs against your patch. The |
John Budorick | 1969858 | 2020-02-14 20:37:38 | [diff] [blame] | 86 | relevant try bots for an iOS patch are `ios-device` and `ios-simulator`. These |
| 87 | bots can be found on the Mac-specific [try server]. A try job is said to succeed |
| 88 | when the build passes (i.e. when the bot successfully compiles and tests the |
| 89 | patch). |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 90 | |
Sylvain Defresne | 37b5787 | 2023-03-16 10:57:05 | [diff] [blame] | 91 | `ios-device` compiles for the iOS device architecture (arm64) and runs no tests. |
John Budorick | 1969858 | 2020-02-14 20:37:38 | [diff] [blame] | 92 | A build is considered successful so long as compilation is successful. |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 93 | |
Sylvain Defresne | 37b5787 | 2023-03-16 10:57:05 | [diff] [blame] | 94 | `ios-simulator` compiles for the iOS simulator architecture (x86_64), and runs |
John Budorick | 1969858 | 2020-02-14 20:37:38 | [diff] [blame] | 95 | tests in the iOS [simulator]. A build is considered successful when both |
| 96 | compilation and all configured tests succeed. |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 97 | |
| 98 | `ios-device` and `ios-simulator` both compile using the version of [clang] |
| 99 | defined by the `CLANG_REVISION` in the Chromium tree. |
| 100 | |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 101 | ### Scheduling try jobs using buildbucket |
| 102 | |
| 103 | Triggering a try job and collecting its results is accomplished using |
| 104 | [buildbucket]. The service allows for build requests to be put into buckets. A |
| 105 | request in this context is a set of properties indicating things such as where |
| 106 | to get the patch. The try bots are set up to poll a particular bucket for build |
| 107 | requests which they execute and post the results of. |
| 108 | |
| 109 | ### Compiling with the analyzer |
| 110 | |
Takuto Ikuta | 7478af72 | 2024-05-27 07:23:19 | [diff] [blame] | 111 | In addition to reclient, the try bots use another time-saving mechanism called |
| 112 | the [analyzer] to determine the subset of compilation targets affected by the |
| 113 | patch that need to be compiled in order to run the affected tests. If a patch is |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 114 | determined not to affect a certain test target, compilation and execution of the |
| 115 | test target will be skipped. |
| 116 | |
| 117 | ## Configuring the bots |
| 118 | |
| 119 | See the [configs code location](#Configs) for where to find the config files for |
| 120 | the bots. The config files are JSON which describe how the bot should compile |
| 121 | and which tests it should run. The config files are located in the configs |
| 122 | directory. The configs directory contains a named directory for each master. For |
| 123 | example: |
| 124 | ```shell |
| 125 | $ ls ios/build/bots |
| 126 | OWNERS scripts tests chromium.fyi chromium.mac |
| 127 | ``` |
| 128 | In this case, configs are defined for iOS bots on [chromium.fyi] and |
| 129 | [chromium.mac]. Inside each master-specific directory are JSON config files |
| 130 | named after each bot. For example: |
| 131 | ```shell |
| 132 | $ ls ios/build/bots/chromium.mac |
| 133 | ios-device.json ios-simulator.json |
| 134 | ``` |
| 135 | The `ios-device` bot on [chromium.mac] will read its configuration from |
| 136 | `chromium.mac/ios-device.json` in the configs directory. |
| 137 | |
| 138 | ### Example |
| 139 | |
| 140 | ```json |
| 141 | { |
| 142 | "comments": [ |
| 143 | "Sample config for a bot." |
| 144 | ], |
| 145 | "gn_args": [ |
| 146 | "is_debug=true", |
Sylvain Defresne | 37b5787 | 2023-03-16 10:57:05 | [diff] [blame] | 147 | "target_cpu=\"x64\"", |
| 148 | "target_environment=\"simulator\"" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 149 | ], |
| 150 | "tests": [ |
| 151 | { |
| 152 | "app": "ios_chrome_unittests", |
| 153 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 154 | "os": "11.0", |
| 155 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 156 | } |
| 157 | ] |
| 158 | } |
| 159 | ``` |
| 160 | The `comments` key is optional and defines a list of strings which can be used |
| 161 | to annotate the config. You may want to explain why the bot exists and what it's |
| 162 | doing, particularly if there are extensive and atypical `gn_args`. |
| 163 | |
| 164 | The `gn_args` key is a required list of arguments to pass to [GN] to generate |
| 165 | the build files. Two GN args are required, `is_debug` and `target_cpu`. Use |
| 166 | `is_debug` to define whether to compile for Debug or Release, and `target_cpu` |
Sylvain Defresne | 37b5787 | 2023-03-16 10:57:05 | [diff] [blame] | 167 | to define whether to compile for x64 or arm64. `target_environment` is used to |
| 168 | define whether to compile for simulator or device (as it cannot be deduced from |
| 169 | the cpu architecture as there exists both x64 and arm64 macOS devices). The iOS |
| 170 | bots typically perform Debug builds for the same architecture as the machine |
| 171 | running the tests (usually x64), and Release builds for arm64. |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 172 | |
| 173 | The `tests` key is an optional list of dictionaries defining tests to run. There |
| 174 | are two types of test dictionary, `app` and `include`. An `app` dict defines a |
| 175 | specific compiled app to run, for example: |
| 176 | ```json |
| 177 | "tests": [ |
| 178 | { |
| 179 | "app": "ios_chrome_unittests", |
| 180 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 181 | "os": "11.0", |
| 182 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 183 | } |
| 184 | ] |
| 185 | ``` |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 186 | |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 187 | This dict says to run `ios_chrome_unittests` on an `iPhone 5s` running iOS |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 188 | `11.0` using Xcode build version `9A235`. A test dict may optionally define a |
| 189 | list of `test args`, which are arguments to pass directly to the test on the |
| 190 | command line, and it may define a boolean value `xctest` to indicate whether the |
| 191 | test is an [xctest] \(default if unspecified is `false`\). For example: |
| 192 | |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 193 | ```json |
| 194 | "tests": [ |
| 195 | { |
| 196 | "app": "ios_chrome_unittests", |
| 197 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 198 | "os": "11.0", |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 199 | "test args": [ |
| 200 | "--foo", |
| 201 | "--bar" |
| 202 | ], |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 203 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 204 | }, |
| 205 | { |
| 206 | "app": "ios_chrome_integration_egtests", |
| 207 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 208 | "os": "11.0", |
| 209 | "xcode build version": "9A235", |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 210 | "xctest": true |
| 211 | } |
| 212 | ] |
| 213 | ``` |
| 214 | This defines two tests to run, first `ios_chrome_unittests` will be run with |
| 215 | `--foo` and `--bar` passed directly to the test on the command line. Next, |
| 216 | `ios_chrome_integration_egtests` will be run as an xctest. `"xctest": true` |
| 217 | must be specified for all xctests, it is an error to try and launch an xctest as |
| 218 | a regular test. |
| 219 | |
| 220 | An `include` dict defines a list of tests to import from the `tests` |
| 221 | subdirectory in the configs directory. For example: |
| 222 | ```json |
| 223 | "tests": [ |
| 224 | { |
| 225 | "include": "common_tests.json", |
| 226 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 227 | "os": "11.0", |
| 228 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 229 | } |
| 230 | ] |
| 231 | ``` |
| 232 | This dict says to import the list of tests from the `tests` subdirectory and run |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 233 | each one on an `iPhone 5s` running iOS `11.0` using Xcode `9A235`. Here's what |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 234 | `common_tests.json` might look like: |
| 235 | ```json |
| 236 | "tests": [ |
| 237 | { |
| 238 | "app": "ios_chrome_unittests" |
| 239 | }, |
| 240 | { |
| 241 | "app": "ios_net_unittests" |
| 242 | }, |
| 243 | { |
| 244 | "app": "ios_web_unittests" |
| 245 | }, |
| 246 | ] |
| 247 | ``` |
| 248 | Includes may contain other keys besides `app` which can then be omitted in the |
| 249 | bot config. For example if `common_tests.json` specifies: |
| 250 | ```json |
| 251 | "tests": [ |
| 252 | { |
| 253 | "app": "ios_chrome_integration_egtests", |
| 254 | "xctest": true, |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 255 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 256 | } |
| 257 | ] |
| 258 | ``` |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 259 | |
| 260 | Then the bot config may omit the `xctest` or `xcode build version` keys, for |
| 261 | example: |
| 262 | |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 263 | ```json |
| 264 | { |
| 265 | "comments": [ |
| 266 | "Sample config for a bot." |
| 267 | ], |
| 268 | "gn_args": [ |
| 269 | "is_debug=true", |
Sylvain Defresne | 37b5787 | 2023-03-16 10:57:05 | [diff] [blame] | 270 | "target_cpu=\"x64\"", |
| 271 | "target_environment=\"simulator\"" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 272 | ], |
| 273 | "tests": [ |
| 274 | { |
| 275 | "include": "common_tests.json", |
| 276 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 277 | "os": "11.0" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 278 | } |
| 279 | ] |
| 280 | } |
| 281 | ``` |
| 282 | Includes are not recursive, so `common_tests.json` may not itself include any |
| 283 | `include` dicts. |
| 284 | |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 285 | Some keywords such as `xcode build version` can also be set globally per build: |
| 286 | |
| 287 | ```json |
| 288 | { |
| 289 | "comments": [ |
| 290 | "Sample config for a bot." |
| 291 | ], |
| 292 | "gn_args": [ |
| 293 | "is_debug=true", |
Sylvain Defresne | 37b5787 | 2023-03-16 10:57:05 | [diff] [blame] | 294 | "target_cpu=\"x64\"", |
| 295 | "target_environment=\"simulator\"" |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame] | 296 | ], |
| 297 | "xcode build version": "9A235", |
| 298 | "tests": [ |
| 299 | { |
| 300 | "app": "ios_chrome_integration_egtests", |
| 301 | "device type": "iPhone 5s", |
| 302 | "os": "11.0" |
| 303 | } |
| 304 | ] |
| 305 | } |
| 306 | ``` |
| 307 | |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 308 | ### Uploading compiled artifacts from a bot |
| 309 | |
| 310 | A bot may be configured to upload compiled artifacts. This is defined by the |
| 311 | `upload` key. For example: |
| 312 | ```json |
| 313 | { |
| 314 | "comments": [ |
| 315 | "Sample config for a bot which uploads artifacts." |
| 316 | ], |
| 317 | "gn_args": [ |
| 318 | "is_debug=true", |
Sylvain Defresne | 37b5787 | 2023-03-16 10:57:05 | [diff] [blame] | 319 | "target_cpu=\"x64\"", |
| 320 | "target_environment=\"simulator\"" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 321 | ], |
| 322 | "upload": [ |
| 323 | { |
| 324 | "artifact": "Chromium.breakpad", |
| 325 | "bucket": "my-gcs-bucket", |
| 326 | }, |
| 327 | { |
| 328 | "artifact": "Chromium.app", |
| 329 | "bucket": "my-gcs-bucket", |
| 330 | "compress": true, |
| 331 | }, |
| 332 | { |
| 333 | "artifact": "Chromium.breakpad", |
smut | 9ea33c6a | 2017-08-23 23:20:35 | [diff] [blame] | 334 | "symupload": "https://clients2.google.com/cr/symbol", |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 335 | } |
| 336 | ] |
| 337 | } |
| 338 | ``` |
| 339 | After compilation, the bot will upload three artifacts. First the |
| 340 | `Chromium.breakpad` symbols will be uploaded to |
| 341 | `gs://my-gcs-bucket/<buildername>/<buildnumber>/Chromium.breakpad`. Next |
| 342 | `Chromium.app` will be tarred, gzipped, and uploaded to |
| 343 | `gs://my-gcs-bucket/<buildername>/<buildnumber>/Chromium.tar.gz`. Finally |
| 344 | the `Chromium.breakpad` symbols will be uploaded to the [breakpad] crash |
| 345 | reporting server where they can be used to symbolicate stack traces. |
| 346 | |
| 347 | If `artifact` is a directory, you must specify `"compress": true`. |
| 348 | |
| 349 | [analyzer]: ../../tools/mb |
| 350 | [breakpad]: https://chromium.googlesource.com/breakpad/breakpad |
| 351 | [buildbucket]: https://cr-buildbucket.appspot.com |
| 352 | [chromium.fyi]: https://build.chromium.org/p/chromium.fyi/waterfall |
| 353 | [chromium.mac]: https://build.chromium.org/p/chromium.mac |
| 354 | [clang]: ../../tools/clang |
| 355 | [commit queue]: https://dev.chromium.org/developers/testing/commit-queue |
| 356 | [gitiles]: https://gerrit.googlesource.com/gitiles |
| 357 | [GN]: ../../tools/gn |
| 358 | [instructions]: ./build_instructions.md |
John Palmer | 046f987 | 2021-05-24 01:24:56 | [diff] [blame] | 359 | [iOS recipes]: https://chromium.googlesource.com/chromium/tools/build/+/main/scripts/slave/recipes/ios |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 360 | [iOS simulator]: ../../testing/iossim |
John Palmer | 046f987 | 2021-05-24 01:24:56 | [diff] [blame] | 361 | [recipe module]: https://chromium.googlesource.com/chromium/tools/build/+/main/scripts/slave/recipe_modules/ios |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 362 | [recipes]: https://chromium.googlesource.com/infra/infra/+/HEAD/doc/users/recipes.md |
| 363 | [simulator]: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/iOS_Simulator_Guide/Introduction/Introduction.html |
| 364 | [src/ios/build/bots]: ../../ios/build/bots |
| 365 | [src/ios/build/bots/scripts]: ../../ios/build/bots/scripts |
John Palmer | 046f987 | 2021-05-24 01:24:56 | [diff] [blame] | 366 | [swarming]: https://chromium.googlesource.com/infra/luci/luci-py/+/main/appengine/swarming/ |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 367 | [swarming server]: https://chromium-swarm.appspot.com |
| 368 | [test runner]: ../../ios/build/bots/scripts/test_runner.py |
| 369 | [tools/build]: https://chromium.googlesource.com/chromium/tools/build |
| 370 | [try job access]: https://www.chromium.org/getting-involved/become-a-committer#TOC-Try-job-access |
| 371 | [try server]: https://build.chromium.org/p/tryserver.chromium.mac/waterfall |
| 372 | [tryserver.chromium.mac]: https://build.chromium.org/p/tryserver.chromium.mac/waterfall |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 373 | [xctest]: https://developer.apple.com/reference/xctest |