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 | |
| 65 | ### Compiling with goma |
| 66 | |
| 67 | Goma is the distributed build system used by Chromium. It reduces compilation |
| 68 | time by avoiding recompilation of objects which have already been compiled |
| 69 | elsewhere. |
| 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 |
| 86 | relevant try bots for an iOS patch are `ios-device`, `ios-device-xcode-clang`, |
| 87 | `ios-simulator`, and `ios-simulator-xcode-clang`. These bots can be found on |
| 88 | the Mac-specific [try server]. A try job is said to succeed when the build |
| 89 | passes (i.e. when the bot successfully compiles and tests the patch). |
| 90 | |
| 91 | `ios-device` and `ios-device-xcode-clang` both compile for the iOS device |
| 92 | architecture (ARM), and neither run any tests. A build is considered successful |
| 93 | so long as compilation is successful. |
| 94 | |
| 95 | `ios-simulator` and `ios-simulator-xcode-clang` both compile for the iOS |
| 96 | simulator architecture (x86), and run tests in the iOS [simulator]. A build is |
| 97 | considered successful when both compilation and all configured test succeed. |
| 98 | |
| 99 | `ios-device` and `ios-simulator` both compile using the version of [clang] |
| 100 | defined by the `CLANG_REVISION` in the Chromium tree. |
| 101 | |
| 102 | `ios-device-xcode-clang` and `ios-simulator-xcode-clang` both compile using the |
| 103 | version of clang that ships with Xcode. |
| 104 | |
| 105 | ### Scheduling try jobs using buildbucket |
| 106 | |
| 107 | Triggering a try job and collecting its results is accomplished using |
| 108 | [buildbucket]. The service allows for build requests to be put into buckets. A |
| 109 | request in this context is a set of properties indicating things such as where |
| 110 | to get the patch. The try bots are set up to poll a particular bucket for build |
| 111 | requests which they execute and post the results of. |
| 112 | |
| 113 | ### Compiling with the analyzer |
| 114 | |
| 115 | In addition to goma, the try bots use another time-saving mechanism called the |
| 116 | [analyzer] to determine the subset of compilation targets affected by the patch |
| 117 | that need to be compiled in order to run the affected tests. If a patch is |
| 118 | determined not to affect a certain test target, compilation and execution of the |
| 119 | test target will be skipped. |
| 120 | |
| 121 | ## Configuring the bots |
| 122 | |
| 123 | See the [configs code location](#Configs) for where to find the config files for |
| 124 | the bots. The config files are JSON which describe how the bot should compile |
| 125 | and which tests it should run. The config files are located in the configs |
| 126 | directory. The configs directory contains a named directory for each master. For |
| 127 | example: |
| 128 | ```shell |
| 129 | $ ls ios/build/bots |
| 130 | OWNERS scripts tests chromium.fyi chromium.mac |
| 131 | ``` |
| 132 | In this case, configs are defined for iOS bots on [chromium.fyi] and |
| 133 | [chromium.mac]. Inside each master-specific directory are JSON config files |
| 134 | named after each bot. For example: |
| 135 | ```shell |
| 136 | $ ls ios/build/bots/chromium.mac |
| 137 | ios-device.json ios-simulator.json |
| 138 | ``` |
| 139 | The `ios-device` bot on [chromium.mac] will read its configuration from |
| 140 | `chromium.mac/ios-device.json` in the configs directory. |
| 141 | |
| 142 | ### Example |
| 143 | |
| 144 | ```json |
| 145 | { |
| 146 | "comments": [ |
| 147 | "Sample config for a bot." |
| 148 | ], |
| 149 | "gn_args": [ |
| 150 | "is_debug=true", |
| 151 | "target_cpu=\"x64\"" |
| 152 | ], |
| 153 | "tests": [ |
| 154 | { |
| 155 | "app": "ios_chrome_unittests", |
| 156 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 157 | "os": "11.0", |
| 158 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 159 | } |
| 160 | ] |
| 161 | } |
| 162 | ``` |
| 163 | The `comments` key is optional and defines a list of strings which can be used |
| 164 | to annotate the config. You may want to explain why the bot exists and what it's |
| 165 | doing, particularly if there are extensive and atypical `gn_args`. |
| 166 | |
| 167 | The `gn_args` key is a required list of arguments to pass to [GN] to generate |
| 168 | the build files. Two GN args are required, `is_debug` and `target_cpu`. Use |
| 169 | `is_debug` to define whether to compile for Debug or Release, and `target_cpu` |
| 170 | to define whether to compile for x86, x64, arm, or arm64. The iOS bots typically |
| 171 | perform Debug builds for x86 and x64, and Release builds for arm and arm64. An |
| 172 | x86/x64 build can only be tested on the [iOS simulator], while an arm/arm64 |
| 173 | build can only be tested on a physical device. |
| 174 | |
| 175 | Since Chromium for iOS is shipped as a [universal binary], it's also fairly |
| 176 | common to set `additional_target_cpus`. For simulator builds, we typically set: |
| 177 | ```json |
| 178 | "gn_args": [ |
| 179 | "additional_target_cpus=[\"x86\"]", |
| 180 | "is_debug=true", |
| 181 | "target_cpu=\"x64\"" |
| 182 | ] |
| 183 | ``` |
| 184 | This builds universal binaries which run in 32-bit mode on 32-bit simulators and |
| 185 | 64-bit mode on 64-bit simulators. For device builds we typically set: |
| 186 | ```json |
| 187 | "gn_args": [ |
| 188 | "additional_target_cpus=[\"arm\"]", |
| 189 | "is_debug=false", |
| 190 | "target_cpu=\"arm64\"" |
| 191 | ] |
| 192 | ``` |
| 193 | In order to build universal binaries which run in 32-bit mode on 32-bit devices |
| 194 | and 64-bit mode on 64-bit devices. |
| 195 | |
| 196 | The `tests` key is an optional list of dictionaries defining tests to run. There |
| 197 | are two types of test dictionary, `app` and `include`. An `app` dict defines a |
| 198 | specific compiled app to run, for example: |
| 199 | ```json |
| 200 | "tests": [ |
| 201 | { |
| 202 | "app": "ios_chrome_unittests", |
| 203 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 204 | "os": "11.0", |
| 205 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 206 | } |
| 207 | ] |
| 208 | ``` |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 209 | |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 210 | 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^] | 211 | `11.0` using Xcode build version `9A235`. A test dict may optionally define a |
| 212 | list of `test args`, which are arguments to pass directly to the test on the |
| 213 | command line, and it may define a boolean value `xctest` to indicate whether the |
| 214 | test is an [xctest] \(default if unspecified is `false`\). For example: |
| 215 | |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 216 | ```json |
| 217 | "tests": [ |
| 218 | { |
| 219 | "app": "ios_chrome_unittests", |
| 220 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 221 | "os": "11.0", |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 222 | "test args": [ |
| 223 | "--foo", |
| 224 | "--bar" |
| 225 | ], |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 226 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 227 | }, |
| 228 | { |
| 229 | "app": "ios_chrome_integration_egtests", |
| 230 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 231 | "os": "11.0", |
| 232 | "xcode build version": "9A235", |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 233 | "xctest": true |
| 234 | } |
| 235 | ] |
| 236 | ``` |
| 237 | This defines two tests to run, first `ios_chrome_unittests` will be run with |
| 238 | `--foo` and `--bar` passed directly to the test on the command line. Next, |
| 239 | `ios_chrome_integration_egtests` will be run as an xctest. `"xctest": true` |
| 240 | must be specified for all xctests, it is an error to try and launch an xctest as |
| 241 | a regular test. |
| 242 | |
| 243 | An `include` dict defines a list of tests to import from the `tests` |
| 244 | subdirectory in the configs directory. For example: |
| 245 | ```json |
| 246 | "tests": [ |
| 247 | { |
| 248 | "include": "common_tests.json", |
| 249 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 250 | "os": "11.0", |
| 251 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 252 | } |
| 253 | ] |
| 254 | ``` |
| 255 | 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^] | 256 | 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] | 257 | `common_tests.json` might look like: |
| 258 | ```json |
| 259 | "tests": [ |
| 260 | { |
| 261 | "app": "ios_chrome_unittests" |
| 262 | }, |
| 263 | { |
| 264 | "app": "ios_net_unittests" |
| 265 | }, |
| 266 | { |
| 267 | "app": "ios_web_unittests" |
| 268 | }, |
| 269 | ] |
| 270 | ``` |
| 271 | Includes may contain other keys besides `app` which can then be omitted in the |
| 272 | bot config. For example if `common_tests.json` specifies: |
| 273 | ```json |
| 274 | "tests": [ |
| 275 | { |
| 276 | "app": "ios_chrome_integration_egtests", |
| 277 | "xctest": true, |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 278 | "xcode build version": "9A235" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 279 | } |
| 280 | ] |
| 281 | ``` |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 282 | |
| 283 | Then the bot config may omit the `xctest` or `xcode build version` keys, for |
| 284 | example: |
| 285 | |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 286 | ```json |
| 287 | { |
| 288 | "comments": [ |
| 289 | "Sample config for a bot." |
| 290 | ], |
| 291 | "gn_args": [ |
| 292 | "is_debug=true", |
| 293 | "target_cpu=\"x64\"" |
| 294 | ], |
| 295 | "tests": [ |
| 296 | { |
| 297 | "include": "common_tests.json", |
| 298 | "device type": "iPhone 5s", |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 299 | "os": "11.0" |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 300 | } |
| 301 | ] |
| 302 | } |
| 303 | ``` |
| 304 | Includes are not recursive, so `common_tests.json` may not itself include any |
| 305 | `include` dicts. |
| 306 | |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 307 | Some keywords such as `xcode build version` can also be set globally per build: |
| 308 | |
| 309 | ```json |
| 310 | { |
| 311 | "comments": [ |
| 312 | "Sample config for a bot." |
| 313 | ], |
| 314 | "gn_args": [ |
| 315 | "is_debug=true", |
| 316 | "target_cpu=\"x64\"" |
| 317 | ], |
| 318 | "xcode build version": "9A235", |
| 319 | "tests": [ |
| 320 | { |
| 321 | "app": "ios_chrome_integration_egtests", |
| 322 | "device type": "iPhone 5s", |
| 323 | "os": "11.0" |
| 324 | } |
| 325 | ] |
| 326 | } |
| 327 | ``` |
| 328 | |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 329 | ### Uploading compiled artifacts from a bot |
| 330 | |
| 331 | A bot may be configured to upload compiled artifacts. This is defined by the |
| 332 | `upload` key. For example: |
| 333 | ```json |
| 334 | { |
| 335 | "comments": [ |
| 336 | "Sample config for a bot which uploads artifacts." |
| 337 | ], |
| 338 | "gn_args": [ |
| 339 | "is_debug=true", |
| 340 | "target_cpu=\"x64\"" |
| 341 | ], |
| 342 | "upload": [ |
| 343 | { |
| 344 | "artifact": "Chromium.breakpad", |
| 345 | "bucket": "my-gcs-bucket", |
| 346 | }, |
| 347 | { |
| 348 | "artifact": "Chromium.app", |
| 349 | "bucket": "my-gcs-bucket", |
| 350 | "compress": true, |
| 351 | }, |
| 352 | { |
| 353 | "artifact": "Chromium.breakpad", |
smut | 9ea33c6a | 2017-08-23 23:20:35 | [diff] [blame] | 354 | "symupload": "https://clients2.google.com/cr/symbol", |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 355 | } |
| 356 | ] |
| 357 | } |
| 358 | ``` |
| 359 | After compilation, the bot will upload three artifacts. First the |
| 360 | `Chromium.breakpad` symbols will be uploaded to |
| 361 | `gs://my-gcs-bucket/<buildername>/<buildnumber>/Chromium.breakpad`. Next |
| 362 | `Chromium.app` will be tarred, gzipped, and uploaded to |
| 363 | `gs://my-gcs-bucket/<buildername>/<buildnumber>/Chromium.tar.gz`. Finally |
| 364 | the `Chromium.breakpad` symbols will be uploaded to the [breakpad] crash |
| 365 | reporting server where they can be used to symbolicate stack traces. |
| 366 | |
| 367 | If `artifact` is a directory, you must specify `"compress": true`. |
| 368 | |
| 369 | [analyzer]: ../../tools/mb |
| 370 | [breakpad]: https://chromium.googlesource.com/breakpad/breakpad |
| 371 | [buildbucket]: https://cr-buildbucket.appspot.com |
| 372 | [chromium.fyi]: https://build.chromium.org/p/chromium.fyi/waterfall |
| 373 | [chromium.mac]: https://build.chromium.org/p/chromium.mac |
| 374 | [clang]: ../../tools/clang |
| 375 | [commit queue]: https://dev.chromium.org/developers/testing/commit-queue |
| 376 | [gitiles]: https://gerrit.googlesource.com/gitiles |
| 377 | [GN]: ../../tools/gn |
| 378 | [instructions]: ./build_instructions.md |
| 379 | [iOS recipes]: https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/slave/recipes/ios |
| 380 | [iOS simulator]: ../../testing/iossim |
| 381 | [recipe module]: https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/slave/recipe_modules/ios |
| 382 | [recipes]: https://chromium.googlesource.com/infra/infra/+/HEAD/doc/users/recipes.md |
| 383 | [simulator]: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/iOS_Simulator_Guide/Introduction/Introduction.html |
| 384 | [src/ios/build/bots]: ../../ios/build/bots |
| 385 | [src/ios/build/bots/scripts]: ../../ios/build/bots/scripts |
Sergey Berezin | 730c59e | 2017-12-21 04:41:53 | [diff] [blame^] | 386 | [swarming]: https://chromium.googlesource.com/infra/luci/luci-py/+/master/appengine/swarming/ |
michaeldo | 8cccf214 | 2017-03-06 22:12:02 | [diff] [blame] | 387 | [swarming server]: https://chromium-swarm.appspot.com |
| 388 | [test runner]: ../../ios/build/bots/scripts/test_runner.py |
| 389 | [tools/build]: https://chromium.googlesource.com/chromium/tools/build |
| 390 | [try job access]: https://www.chromium.org/getting-involved/become-a-committer#TOC-Try-job-access |
| 391 | [try server]: https://build.chromium.org/p/tryserver.chromium.mac/waterfall |
| 392 | [tryserver.chromium.mac]: https://build.chromium.org/p/tryserver.chromium.mac/waterfall |
| 393 | [universal binary]: https://en.wikipedia.org/wiki/Universal_binary |
| 394 | [xctest]: https://developer.apple.com/reference/xctest |