| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 Universal manifests for Mozilla test harnesses | 
|  | 2 | 
|  | 3 # What is ManifestDestiny? | 
|  | 4 | 
|  | 5 What ManifestDestiny gives you: | 
|  | 6 | 
|  | 7 * manifests are ordered lists of tests | 
|  | 8 * tests may have an arbitrary number of key, value pairs | 
|  | 9 * the parser returns an ordered list of test data structures, which | 
|  | 10   are just dicts with some keys.  For example, a test with no | 
|  | 11   user-specified metadata looks like this: | 
|  | 12 | 
|  | 13     [{'expected': 'pass', | 
|  | 14       'path': '/home/mozilla/mozmill/src/ManifestDestiny/manifestdestiny/tests/t
     estToolbar/testBackForwardButtons.js', | 
|  | 15       'relpath': 'testToolbar/testBackForwardButtons.js', | 
|  | 16       'name': 'testBackForwardButtons.js', | 
|  | 17       'here': '/home/mozilla/mozmill/src/ManifestDestiny/manifestdestiny/tests', | 
|  | 18       'manifest': '/home/mozilla/mozmill/src/ManifestDestiny/manifestdestiny/tes
     ts/manifest.ini',}] | 
|  | 19 | 
|  | 20 The keys displayed here (path, relpath, name, here, and manifest) are reserved k
     eys for ManifestDestiny and any consuming APIs.  You can add additional key, val
     ue metadata to each test. | 
|  | 21 | 
|  | 22 | 
|  | 23 # Why have test manifests? | 
|  | 24 | 
|  | 25 It is desirable to have a unified format for test manifests for testing | 
|  | 26 [mozilla-central](http://hg.mozilla.org/mozilla-central), etc. | 
|  | 27 | 
|  | 28 * It is desirable to be able to selectively enable or disable tests based on pla
     tform or other conditions. This should be easy to do. Currently, since many of t
     he harnesses just crawl directories, there is no effective way of disabling a te
     st except for removal from mozilla-central | 
|  | 29 * It is desriable to do this in a universal way so that enabling and disabling t
     ests as well as other tasks are easily accessible to a wider audience than just 
     those intimately familiar with the specific test framework. | 
|  | 30 * It is desirable to have other metadata on top of the test. For instance, let's
      say a test is marked as skipped. It would be nice to give the reason why. | 
|  | 31 | 
|  | 32 | 
|  | 33 Most Mozilla test harnesses work by crawling a directory structure. | 
|  | 34 While this is straight-forward, manifests offer several practical | 
|  | 35 advantages:: | 
|  | 36 | 
|  | 37 * ability to turn a test off easily: if a test is broken on m-c | 
|  | 38   currently, the only way to turn it off, generally speaking, is just | 
|  | 39   removing the test.  Often this is undesirable, as if the test should | 
|  | 40   be dismissed because other people want to land and it can't be | 
|  | 41   investigated in real time (is it a failure? is the test bad? is no | 
|  | 42   one around that knows the test?), then backing out a test is at best | 
|  | 43   problematic.  With a manifest, a test may be disabled without | 
|  | 44   removing it from the tree and a bug filed with the appropriate | 
|  | 45   reason: | 
|  | 46 | 
|  | 47      [test_broken.js] | 
|  | 48      disabled = https://bugzilla.mozilla.org/show_bug.cgi?id=123456 | 
|  | 49 | 
|  | 50 * ability to run different (subsets of) tests on different | 
|  | 51   platforms. Traditionally, we've done a bit of magic or had the test | 
|  | 52   know what platform it would or would not run on. With manifests, you | 
|  | 53   can mark what platforms a test will or will not run on and change | 
|  | 54   these without changing the test. | 
|  | 55 | 
|  | 56      [test_works_on_windows_only.js] | 
|  | 57      run-if = os == 'win' | 
|  | 58 | 
|  | 59 * ability to markup tests with metadata. We have a large, complicated, | 
|  | 60   and always changing infrastructure.  key, value metadata may be used | 
|  | 61   as an annotation to a test and appropriately curated and mined.  For | 
|  | 62   instance, we could mark certain tests as randomorange with a bug | 
|  | 63   number, if it were desirable. | 
|  | 64 | 
|  | 65 * ability to have sane and well-defined test-runs. You can keep | 
|  | 66   different manifests for different test runs and ``[include:]`` | 
|  | 67   (sub)manifests as appropriate to your needs. | 
|  | 68 | 
|  | 69 | 
|  | 70 # Manifest Format | 
|  | 71 | 
|  | 72 Manifests are .ini file with the section names denoting the path | 
|  | 73 relative to the manifest: | 
|  | 74 | 
|  | 75     [foo.js] | 
|  | 76     [bar.js] | 
|  | 77     [fleem.js] | 
|  | 78 | 
|  | 79 The sections are read in order. In addition, tests may include | 
|  | 80 arbitrary key, value metadata to be used by the harness.  You may also | 
|  | 81 have a `[DEFAULT]` section that will give key, value pairs that will | 
|  | 82 be inherited by each test unless overridden: | 
|  | 83 | 
|  | 84     [DEFAULT] | 
|  | 85     type = restart | 
|  | 86 | 
|  | 87     [lilies.js] | 
|  | 88     color = white | 
|  | 89 | 
|  | 90     [daffodils.js] | 
|  | 91     color = yellow | 
|  | 92     type = other | 
|  | 93     # override type from DEFAULT | 
|  | 94 | 
|  | 95     [roses.js] | 
|  | 96     color = red | 
|  | 97 | 
|  | 98 You can also include other manifests: | 
|  | 99 | 
|  | 100     [include:subdir/anothermanifest.ini] | 
|  | 101 | 
|  | 102 Manifests are included relative to the directory of the manifest with | 
|  | 103 the `[include:]` directive unless they are absolute paths. | 
|  | 104 | 
|  | 105 | 
|  | 106 # Data | 
|  | 107 | 
|  | 108 Manifest Destiny gives tests as a list of dictionaries (in python | 
|  | 109 terms). | 
|  | 110 | 
|  | 111 * path: full path to the test | 
|  | 112 * relpath: relative path starting from the root manifest location | 
|  | 113 * name: file name of the test | 
|  | 114 * here: the parent directory of the manifest | 
|  | 115 * manifest: the path to the manifest containing the test | 
|  | 116 | 
|  | 117 This data corresponds to a one-line manifest: | 
|  | 118 | 
|  | 119     [testToolbar/testBackForwardButtons.js] | 
|  | 120 | 
|  | 121 If additional key, values were specified, they would be in this dict | 
|  | 122 as well. | 
|  | 123 | 
|  | 124 Outside of the reserved keys, the remaining key, values | 
|  | 125 are up to convention to use.  There is a (currently very minimal) | 
|  | 126 generic integration layer in ManifestDestiny for use of all harnesses, | 
|  | 127 `manifestparser.TestManifest`. | 
|  | 128 For instance, if the 'disabled' key is present, you can get the set of | 
|  | 129 tests without disabled (various other queries are doable as well). | 
|  | 130 | 
|  | 131 Since the system is convention-based, the harnesses may do whatever | 
|  | 132 they want with the data.  They may ignore it completely, they may use | 
|  | 133 the provided integration layer, or they may provide their own | 
|  | 134 integration layer.  This should allow whatever sort of logic is | 
|  | 135 desired.  For instance, if in yourtestharness you wanted to run only on | 
|  | 136 mondays for a certain class of tests: | 
|  | 137 | 
|  | 138     tests = [] | 
|  | 139     for test in manifests.tests: | 
|  | 140         if 'runOnDay' in test: | 
|  | 141            if calendar.day_name[calendar.weekday(*datetime.datetime.now().timetu
     ple()[:3])].lower() == test['runOnDay'].lower(): | 
|  | 142                tests.append(test) | 
|  | 143         else: | 
|  | 144            tests.append(test) | 
|  | 145 | 
|  | 146 To recap: | 
|  | 147 * the manifests allow you to specify test data | 
|  | 148 * the parser gives you this data | 
|  | 149 * you can use it however you want or process it further as you need | 
|  | 150 | 
|  | 151 Tests are denoted by sections in an .ini file (see | 
|  | 152 http://hg.mozilla.org/automation/ManifestDestiny/file/tip/manifestdestiny/tests/
     mozmill-example.ini). | 
|  | 153 | 
|  | 154 Additional manifest files may be included with an `[include:]` directive: | 
|  | 155 | 
|  | 156     [include:path-to-additional-file.manifest] | 
|  | 157 | 
|  | 158 The path to included files is relative to the current manifest. | 
|  | 159 | 
|  | 160 The `[DEFAULT]` section contains variables that all tests inherit from. | 
|  | 161 | 
|  | 162 Included files will inherit the top-level variables but may override | 
|  | 163 in their own `[DEFAULT]` section. | 
|  | 164 | 
|  | 165 | 
|  | 166 # ManifestDestiny Architecture | 
|  | 167 | 
|  | 168 There is a two- or three-layered approach to the ManifestDestiny | 
|  | 169 architecture, depending on your needs: | 
|  | 170 | 
|  | 171 1. ManifestParser: this is a generic parser for .ini manifests that | 
|  | 172 facilitates the `[include:]` logic and the inheritence of | 
|  | 173 metadata. Despite the internal variable being called `self.tests` | 
|  | 174 (an oversight), this layer has nothing in particular to do with tests. | 
|  | 175 | 
|  | 176 2. TestManifest: this is a harness-agnostic integration layer that is | 
|  | 177 test-specific. TestManifest faciliates `skip-if` and `run-if` logic. | 
|  | 178 | 
|  | 179 3. Optionally, a harness will have an integration layer than inherits | 
|  | 180 from TestManifest if more harness-specific customization is desired at | 
|  | 181 the manifest level. | 
|  | 182 | 
|  | 183 See the source code at https://github.com/mozilla/mozbase/tree/master/manifestde
     stiny | 
|  | 184 and | 
|  | 185 https://github.com/mozilla/mozbase/blob/master/manifestdestiny/manifestparser.py | 
|  | 186 in particular. | 
|  | 187 | 
|  | 188 | 
|  | 189 # Using Manifests | 
|  | 190 | 
|  | 191 A test harness will normally call `TestManifest.active_tests`: | 
|  | 192 | 
|  | 193     def active_tests(self, exists=True, disabled=True, **tags): | 
|  | 194 | 
|  | 195 The manifests are passed to the `__init__` or `read` methods with | 
|  | 196 appropriate arguments.  `active_tests` then allows you to select the | 
|  | 197 tests you want: | 
|  | 198 | 
|  | 199 - exists : return only existing tests | 
|  | 200 - disabled : whether to return disabled tests; if not these will be | 
|  | 201   filtered out; if True (the default), the `disabled` key of a | 
|  | 202   test's metadata will be present and will be set to the reason that a | 
|  | 203   test is disabled | 
|  | 204 - tags : keys and values to filter on (e.g. `os='linux'`) | 
|  | 205 | 
|  | 206 `active_tests` looks for tests with `skip-if` | 
|  | 207 `run-if`.  If the condition is or is not fulfilled, | 
|  | 208 respectively, the test is marked as disabled.  For instance, if you | 
|  | 209 pass `**dict(os='linux')` as `**tags`, if a test contains a line | 
|  | 210 `skip-if = os == 'linux'` this test will be disabled, or | 
|  | 211 `run-if = os = 'win'` in which case the test will also be disabled.  It | 
|  | 212 is up to the harness to pass in tags appropriate to its usage. | 
|  | 213 | 
|  | 214 | 
|  | 215 # Creating Manifests | 
|  | 216 | 
|  | 217 ManifestDestiny comes with a console script, `manifestparser create`, that | 
|  | 218 may be used to create a seed manifest structure from a directory of | 
|  | 219 files.  Run `manifestparser help create` for usage information. | 
|  | 220 | 
|  | 221 | 
|  | 222 # Copying Manifests | 
|  | 223 | 
|  | 224 To copy tests and manifests from a source: | 
|  | 225 | 
|  | 226     manifestparser [options] copy from_manifest to_directory -tag1 -tag2 --key1=
     value1 key2=value2 ... | 
|  | 227 | 
|  | 228 | 
|  | 229 # Upating Tests | 
|  | 230 | 
|  | 231 To update the tests associated with with a manifest from a source | 
|  | 232 directory: | 
|  | 233 | 
|  | 234     manifestparser [options] update manifest from_directory -tag1 -tag2 --key1=v
     alue1 --key2=value2 ... | 
|  | 235 | 
|  | 236 | 
|  | 237 # Usage example | 
|  | 238 | 
|  | 239 Here is an example of how to create manifests for a directory tree and | 
|  | 240 update the tests listed in the manifests from an external source. | 
|  | 241 | 
|  | 242 ## Creating Manifests | 
|  | 243 | 
|  | 244 Let's say you want to make a series of manifests for a given directory structure
      containing `.js` test files: | 
|  | 245 | 
|  | 246     testing/mozmill/tests/firefox/ | 
|  | 247     testing/mozmill/tests/firefox/testAwesomeBar/ | 
|  | 248     testing/mozmill/tests/firefox/testPreferences/ | 
|  | 249     testing/mozmill/tests/firefox/testPrivateBrowsing/ | 
|  | 250     testing/mozmill/tests/firefox/testSessionStore/ | 
|  | 251     testing/mozmill/tests/firefox/testTechnicalTools/ | 
|  | 252     testing/mozmill/tests/firefox/testToolbar/ | 
|  | 253     testing/mozmill/tests/firefox/restartTests | 
|  | 254 | 
|  | 255 You can use `manifestparser create` to do this: | 
|  | 256 | 
|  | 257     $ manifestparser help create | 
|  | 258     Usage: manifestparser.py [options] create directory <directory> <...> | 
|  | 259 | 
|  | 260          create a manifest from a list of directories | 
|  | 261 | 
|  | 262     Options: | 
|  | 263       -p PATTERN, --pattern=PATTERN | 
|  | 264                             glob pattern for files | 
|  | 265       -i IGNORE, --ignore=IGNORE | 
|  | 266                             directories to ignore | 
|  | 267       -w IN_PLACE, --in-place=IN_PLACE | 
|  | 268                             Write .ini files in place; filename to write to | 
|  | 269 | 
|  | 270 We only want `.js` files and we want to skip the `restartTests` directory. | 
|  | 271 We also want to write a manifest per directory, so I use the `--in-place` | 
|  | 272 option to write the manifests: | 
|  | 273 | 
|  | 274     manifestparser create . -i restartTests -p '*.js' -w manifest.ini | 
|  | 275 | 
|  | 276 This creates a manifest.ini per directory that we care about with the JS test fi
     les: | 
|  | 277 | 
|  | 278     testing/mozmill/tests/firefox/manifest.ini | 
|  | 279     testing/mozmill/tests/firefox/testAwesomeBar/manifest.ini | 
|  | 280     testing/mozmill/tests/firefox/testPreferences/manifest.ini | 
|  | 281     testing/mozmill/tests/firefox/testPrivateBrowsing/manifest.ini | 
|  | 282     testing/mozmill/tests/firefox/testSessionStore/manifest.ini | 
|  | 283     testing/mozmill/tests/firefox/testTechnicalTools/manifest.ini | 
|  | 284     testing/mozmill/tests/firefox/testToolbar/manifest.ini | 
|  | 285 | 
|  | 286 The top-level `manifest.ini` merely has `[include:]` references to the sub manif
     ests: | 
|  | 287 | 
|  | 288     [include:testAwesomeBar/manifest.ini] | 
|  | 289     [include:testPreferences/manifest.ini] | 
|  | 290     [include:testPrivateBrowsing/manifest.ini] | 
|  | 291     [include:testSessionStore/manifest.ini] | 
|  | 292     [include:testTechnicalTools/manifest.ini] | 
|  | 293     [include:testToolbar/manifest.ini] | 
|  | 294 | 
|  | 295 Each sub-level manifest contains the (`.js`) test files relative to it. | 
|  | 296 | 
|  | 297 ## Updating the tests from manifests | 
|  | 298 | 
|  | 299 You may need to update tests as given in manifests from a different source direc
     tory. | 
|  | 300 `manifestparser update` was made for just this purpose: | 
|  | 301 | 
|  | 302     Usage: manifestparser [options] update manifest directory -tag1 -tag2 --key1
     =value1 --key2=value2 ... | 
|  | 303 | 
|  | 304         update the tests as listed in a manifest from a directory | 
|  | 305 | 
|  | 306 To update from a directory of tests in `~/mozmill/src/mozmill-tests/firefox/` ru
     n: | 
|  | 307 | 
|  | 308     manifestparser update manifest.ini ~/mozmill/src/mozmill-tests/firefox/ | 
|  | 309 | 
|  | 310 | 
|  | 311 # Tests | 
|  | 312 | 
|  | 313 ManifestDestiny includes a suite of tests: | 
|  | 314 | 
|  | 315 https://github.com/mozilla/mozbase/tree/master/manifestdestiny/tests | 
|  | 316 | 
|  | 317 `test_manifest.txt` is a doctest that may be helpful in figuring out | 
|  | 318 how to use the API.  Tests are run via `python test.py`. | 
|  | 319 | 
|  | 320 | 
|  | 321 # Bugs | 
|  | 322 | 
|  | 323 Please file any bugs or feature requests at | 
|  | 324 | 
|  | 325 https://bugzilla.mozilla.org/enter_bug.cgi?product=Testing&component=ManifestPar
     ser | 
|  | 326 | 
|  | 327 Or contact jhammel @mozilla.org or in #ateam on irc.mozilla.org | 
|  | 328 | 
|  | 329 | 
|  | 330 # CLI | 
|  | 331 | 
|  | 332 Run `manifestparser help` for usage information. | 
|  | 333 | 
|  | 334 To create a manifest from a set of directories: | 
|  | 335 | 
|  | 336     manifestparser [options] create directory <directory> <...> [create-options] | 
|  | 337 | 
|  | 338 To output a manifest of tests: | 
|  | 339 | 
|  | 340     manifestparser [options] write manifest <manifest> <...> -tag1 -tag2 --key1=
     value1 --key2=value2 ... | 
|  | 341 | 
|  | 342 To copy tests and manifests from a source: | 
|  | 343 | 
|  | 344     manifestparser [options] copy from_manifest to_manifest -tag1 -tag2 --key1=v
     alue1 key2=value2 ... | 
|  | 345 | 
|  | 346 To update the tests associated with with a manifest from a source | 
|  | 347 directory: | 
|  | 348 | 
|  | 349     manifestparser [options] update manifest from_directory -tag1 -tag2 --key1=v
     alue1 --key2=value2 ... | 
|  | 350 | 
|  | 351 | 
|  | 352 # Design Considerations | 
|  | 353 | 
|  | 354 Contrary to some opinion, manifestparser.py and the associated .ini | 
|  | 355 format were not magically plucked from the sky but were descended upon | 
|  | 356 through several design considerations. | 
|  | 357 | 
|  | 358 * test manifests should be ordered.  While python 2.6 and greater has | 
|  | 359   a ConfigParser that can use an ordered dictionary, it is a | 
|  | 360   requirement that we support python 2.4 for the build + testing | 
|  | 361   environment.  To that end, a `read_ini` function was implemented | 
|  | 362   in manifestparser.py that should be the equivalent of the .ini | 
|  | 363   dialect used by ConfigParser. | 
|  | 364 | 
|  | 365 * the manifest format should be easily human readable/writable.  While | 
|  | 366   there was initially some thought of using JSON, there was pushback | 
|  | 367   that JSON was not easily editable.  An ideal manifest format would | 
|  | 368   degenerate to a line-separated list of files.  While .ini format | 
|  | 369   requires an additional `[]` per line, and while there have been | 
|  | 370   complaints about this, hopefully this is good enough. | 
|  | 371 | 
|  | 372 * python does not have an in-built YAML parser.  Since it was | 
|  | 373   undesirable for manifestparser.py to have any dependencies, YAML was | 
|  | 374   dismissed as a format. | 
|  | 375 | 
|  | 376 * we could have used a proprietary format but decided against it. | 
|  | 377   Everyone knows .ini and there are good tools to deal with it. | 
|  | 378   However, since read_ini is the only function that transforms a | 
|  | 379   manifest to a list of key, value pairs, while the implications for | 
|  | 380   changing the format impacts downstream code, doing so should be | 
|  | 381   programmatically simple. | 
|  | 382 | 
|  | 383 * there should be a single file that may easily be | 
|  | 384   transported. Traditionally, test harnesses have lived in | 
|  | 385   mozilla-central. This is less true these days and it is increasingly | 
|  | 386   likely that more tests will not live in mozilla-central going | 
|  | 387   forward.  So `manifestparser.py` should be highly consumable. To | 
|  | 388   this end, it is a single file, as appropriate to mozilla-central, | 
|  | 389   which is also a working python package deployed to PyPI for easy | 
|  | 390   installation. | 
|  | 391 | 
|  | 392 | 
|  | 393 # Developing ManifestDestiny | 
|  | 394 | 
|  | 395 ManifestDestiny is developed and maintained by Mozilla's | 
|  | 396 [Automation and Testing Team](https://wiki.mozilla.org/Auto-tools). | 
|  | 397 The project page is located at | 
|  | 398 https://wiki.mozilla.org/Auto-tools/Projects/ManifestDestiny . | 
|  | 399 | 
|  | 400 | 
|  | 401 # Historical Reference | 
|  | 402 | 
|  | 403 Date-ordered list of links about how manifests came to be where they are today:: | 
|  | 404 | 
|  | 405 * https://wiki.mozilla.org/Auto-tools/Projects/UniversalManifest | 
|  | 406 * http://alice.nodelman.net/blog/post/2010/05/ | 
|  | 407 * http://alice.nodelman.net/blog/post/universal-manifest-for-unit-tests-a-propos
     al/ | 
|  | 408 * https://elvis314.wordpress.com/2010/07/05/improving-personal-hygiene-by-adjust
     ing-mochitests/ | 
|  | 409 * https://elvis314.wordpress.com/2010/07/27/types-of-data-we-care-about-in-a-man
     ifest/ | 
|  | 410 * https://bugzilla.mozilla.org/show_bug.cgi?id=585106 | 
|  | 411 * http://elvis314.wordpress.com/2011/05/20/converting-xpcshell-from-listing-dire
     ctories-to-a-manifest/ | 
|  | 412 * https://bugzilla.mozilla.org/show_bug.cgi?id=616999 | 
|  | 413 * https://wiki.mozilla.org/Auto-tools/Projects/ManifestDestiny | 
|  | 414 * https://developer.mozilla.org/en/Writing_xpcshell-based_unit_tests#Adding_your
     _tests_to_the_xpcshell_manifest | 
| OLD | NEW | 
|---|