testing/mozbase/docs/manifestdestiny.rst

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 Managing lists of tests
     2 =======================
     4 We don't always want to run all tests, all the time. Sometimes a test
     5 may be broken, in other cases we only want to run a test on a specific
     6 platform or build of Mozilla. To handle these cases (and more), we
     7 created a python library to create and use test "manifests", which
     8 codify this information.
    10 :mod:`manifestdestiny` --- Create and manage test manifests
    11 -----------------------------------------------------------
    13 manifestdestiny lets you easily create and use test manifests, to
    14 control which tests are run under what circumstances.
    16 What ManifestDestiny gives you:
    18 * manifests are ordered lists of tests
    19 * tests may have an arbitrary number of key, value pairs
    20 * the parser returns an ordered list of test data structures, which
    21   are just dicts with some keys.  For example, a test with no
    22   user-specified metadata looks like this:
    24 .. code-block:: text
    26     [{'expected': 'pass',
    27       'path': '/home/mozilla/mozmill/src/ManifestDestiny/manifestdestiny/tests/testToolbar/testBackForwardButtons.js',
    28       'relpath': 'testToolbar/testBackForwardButtons.js',
    29       'name': 'testBackForwardButtons.js',
    30       'here': '/home/mozilla/mozmill/src/ManifestDestiny/manifestdestiny/tests',
    31       'manifest': '/home/mozilla/mozmill/src/ManifestDestiny/manifestdestiny/tests/manifest.ini',}]
    33 The keys displayed here (path, relpath, name, here, and manifest) are
    34 reserved keys for ManifestDestiny and any consuming APIs.  You can add
    35 additional key, value metadata to each test.
    37 Why have test manifests?
    38 ````````````````````````
    40 It is desirable to have a unified format for test manifests for testing
    41 [mozilla-central](http://hg.mozilla.org/mozilla-central), etc.
    43 * It is desirable to be able to selectively enable or disable tests based on platform or other conditions. This should be easy to do. Currently, since many of the harnesses just crawl directories, there is no effective way of disabling a test except for removal from mozilla-central
    44 * It is desriable to do this in a universal way so that enabling and disabling tests as well as other tasks are easily accessible to a wider audience than just those intimately familiar with the specific test framework.
    45 * 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.
    48 Most Mozilla test harnesses work by crawling a directory structure.
    49 While this is straight-forward, manifests offer several practical
    50 advantages:
    52 * ability to turn a test off easily: if a test is broken on m-c
    53   currently, the only way to turn it off, generally speaking, is just
    54   removing the test.  Often this is undesirable, as if the test should
    55   be dismissed because other people want to land and it can't be
    56   investigated in real time (is it a failure? is the test bad? is no
    57   one around that knows the test?), then backing out a test is at best
    58   problematic.  With a manifest, a test may be disabled without
    59   removing it from the tree and a bug filed with the appropriate
    60   reason:
    62 .. code-block:: text
    64      [test_broken.js]
    65      disabled = https://bugzilla.mozilla.org/show_bug.cgi?id=123456
    67 * ability to run different (subsets of) tests on different
    68   platforms. Traditionally, we've done a bit of magic or had the test
    69   know what platform it would or would not run on. With manifests, you
    70   can mark what platforms a test will or will not run on and change
    71   these without changing the test.
    73 .. code-block:: text
    75      [test_works_on_windows_only.js]
    76      run-if = os == 'win'
    78 * ability to markup tests with metadata. We have a large, complicated,
    79   and always changing infrastructure.  key, value metadata may be used
    80   as an annotation to a test and appropriately curated and mined.  For
    81   instance, we could mark certain tests as randomorange with a bug
    82   number, if it were desirable.
    84 * ability to have sane and well-defined test-runs. You can keep
    85   different manifests for different test runs and ``[include:]``
    86   (sub)manifests as appropriate to your needs.
    88 Manifest Format
    89 ````````
    91 Manifests are .ini file with the section names denoting the path
    92 relative to the manifest:
    94 .. code-block:: text
    96     [foo.js]
    97     [bar.js]
    98     [fleem.js]
   100 The sections are read in order. In addition, tests may include
   101 arbitrary key, value metadata to be used by the harness.  You may also
   102 have a `[DEFAULT]` section that will give key, value pairs that will
   103 be inherited by each test unless overridden:
   105 .. code-block:: text
   107     [DEFAULT]
   108     type = restart
   110     [lilies.js]
   111     color = white
   113     [daffodils.js]
   114     color = yellow
   115     type = other
   116     # override type from DEFAULT
   118     [roses.js]
   119     color = red
   121 You can also include other manifests:
   123 .. code-block:: text
   125     [include:subdir/anothermanifest.ini]
   127 Manifests are included relative to the directory of the manifest with
   128 the `[include:]` directive unless they are absolute paths.
   130 By default you can use both '#' and ';' as comment characters. Comments
   131 must start on a new line, inline comments are not supported.
   133 .. code-block:: text
   135     [roses.js]
   136     # a valid comment
   137     ; another valid comment
   138     color = red # not a valid comment
   140 In the example above, the 'color' property will have the value 'red #
   141 not a valid comment'.
   143 Manifest Conditional Expressions
   144 ````````````````````````````````
   145 The conditional expressions used in manifests are parsed using the *ExpressionParser* class.
   147 .. autoclass:: manifestparser.ExpressionParser
   149 Consumers of this module are expected to pass in a value dictionary
   150 for evaluating conditional expressions. A common pattern is to pass
   151 the dictionary from the :mod:`mozinfo` module.
   153 Data
   154 ````
   156 Manifest Destiny gives tests as a list of dictionaries (in python
   157 terms).
   159 * path: full path to the test
   160 * relpath: relative path starting from the root manifest location
   161 * name: file name of the test
   162 * here: the parent directory of the manifest
   163 * manifest: the path to the manifest containing the test
   165 This data corresponds to a one-line manifest:
   167 .. code-block:: text
   169     [testToolbar/testBackForwardButtons.js]
   171 If additional key, values were specified, they would be in this dict
   172 as well.
   174 Outside of the reserved keys, the remaining key, values
   175 are up to convention to use.  There is a (currently very minimal)
   176 generic integration layer in ManifestDestiny for use of all harnesses,
   177 `manifestparser.TestManifest`.
   178 For instance, if the 'disabled' key is present, you can get the set of
   179 tests without disabled (various other queries are doable as well).
   181 Since the system is convention-based, the harnesses may do whatever
   182 they want with the data.  They may ignore it completely, they may use
   183 the provided integration layer, or they may provide their own
   184 integration layer.  This should allow whatever sort of logic is
   185 desired.  For instance, if in yourtestharness you wanted to run only on
   186 mondays for a certain class of tests:
   188 .. code-block:: text
   190     tests = []
   191     for test in manifests.tests:
   192         if 'runOnDay' in test:
   193            if calendar.day_name[calendar.weekday(*datetime.datetime.now().timetuple()[:3])].lower() == test['runOnDay'].lower():
   194                tests.append(test)
   195         else:
   196            tests.append(test)
   198 To recap:
   199 * the manifests allow you to specify test data
   200 * the parser gives you this data
   201 * you can use it however you want or process it further as you need
   203 Tests are denoted by sections in an .ini file (see
   204 http://hg.mozilla.org/automation/ManifestDestiny/file/tip/manifestdestiny/tests/mozmill-example.ini).
   206 Additional manifest files may be included with an `[include:]` directive:
   208 .. code-block:: text
   210     [include:path-to-additional-file.manifest]
   212 The path to included files is relative to the current manifest.
   214 The `[DEFAULT]` section contains variables that all tests inherit from.
   216 Included files will inherit the top-level variables but may override
   217 in their own `[DEFAULT]` section.
   219 ManifestDestiny Architecture
   220 ````````````````````````````
   222 There is a two- or three-layered approach to the ManifestDestiny
   223 architecture, depending on your needs:
   225 1. ManifestParser: this is a generic parser for .ini manifests that
   226 facilitates the `[include:]` logic and the inheritence of
   227 metadata. Despite the internal variable being called `self.tests`
   228 (an oversight), this layer has nothing in particular to do with tests.
   230 2. TestManifest: this is a harness-agnostic integration layer that is
   231 test-specific. TestManifest faciliates `skip-if` and `run-if` logic.
   233 3. Optionally, a harness will have an integration layer than inherits
   234 from TestManifest if more harness-specific customization is desired at
   235 the manifest level.
   237 See the source code at https://github.com/mozilla/mozbase/tree/master/manifestdestiny
   238 and
   239 https://github.com/mozilla/mozbase/blob/master/manifestdestiny/manifestparser.py
   240 in particular.
   242 Using Manifests
   243 ```````````````
   245 A test harness will normally call `TestManifest.active_tests`:
   247 .. code-block:: text
   249     def active_tests(self, exists=True, disabled=True, **tags):
   251 The manifests are passed to the `__init__` or `read` methods with
   252 appropriate arguments.  `active_tests` then allows you to select the
   253 tests you want:
   255 - exists : return only existing tests
   256 - disabled : whether to return disabled tests; if not these will be
   257   filtered out; if True (the default), the `disabled` key of a
   258   test's metadata will be present and will be set to the reason that a
   259   test is disabled
   260 - tags : keys and values to filter on (e.g. `os='linux'`)
   262 `active_tests` looks for tests with `skip-if`
   263 `run-if`.  If the condition is or is not fulfilled,
   264 respectively, the test is marked as disabled.  For instance, if you
   265 pass `**dict(os='linux')` as `**tags`, if a test contains a line
   266 `skip-if = os == 'linux'` this test will be disabled, or
   267 `run-if = os = 'win'` in which case the test will also be disabled.  It
   268 is up to the harness to pass in tags appropriate to its usage.
   270 Creating Manifests
   271 ``````````````````
   273 ManifestDestiny comes with a console script, `manifestparser create`, that
   274 may be used to create a seed manifest structure from a directory of
   275 files.  Run `manifestparser help create` for usage information.
   277 Copying Manifests
   278 `````````````````
   280 To copy tests and manifests from a source:
   282 .. code-block:: text
   284     manifestparser [options] copy from_manifest to_directory -tag1 -tag2 `key1=value1 key2=value2 ...
   286 Updating Tests
   287 ``````````````
   289 To update the tests associated with with a manifest from a source
   290 directory:
   292 .. code-block:: text
   294     manifestparser [options] update manifest from_directory -tag1 -tag2 `key1=value1 `key2=value2 ...
   296 Usage example
   297 `````````````
   299 Here is an example of how to create manifests for a directory tree and
   300 update the tests listed in the manifests from an external source.
   302 Creating Manifests
   303 ``````````````````
   305 Let's say you want to make a series of manifests for a given directory structure containing `.js` test files:
   307 .. code-block:: text
   309     testing/mozmill/tests/firefox/
   310     testing/mozmill/tests/firefox/testAwesomeBar/
   311     testing/mozmill/tests/firefox/testPreferences/
   312     testing/mozmill/tests/firefox/testPrivateBrowsing/
   313     testing/mozmill/tests/firefox/testSessionStore/
   314     testing/mozmill/tests/firefox/testTechnicalTools/
   315     testing/mozmill/tests/firefox/testToolbar/
   316     testing/mozmill/tests/firefox/restartTests
   318 You can use `manifestparser create` to do this:
   320 .. code-block:: text
   322     $ manifestparser help create
   323     Usage: manifestparser.py [options] create directory <directory> <...>
   325          create a manifest from a list of directories
   327     Options:
   328       -p PATTERN, `pattern=PATTERN
   329                             glob pattern for files
   330       -i IGNORE, `ignore=IGNORE
   331                             directories to ignore
   332       -w IN_PLACE, --in-place=IN_PLACE
   333                             Write .ini files in place; filename to write to
   335 We only want `.js` files and we want to skip the `restartTests` directory.
   336 We also want to write a manifest per directory, so I use the `--in-place`
   337 option to write the manifests:
   339 .. code-block:: text
   341     manifestparser create . -i restartTests -p '*.js' -w manifest.ini
   343 This creates a manifest.ini per directory that we care about with the JS test files:
   345 .. code-block:: text
   347     testing/mozmill/tests/firefox/manifest.ini
   348     testing/mozmill/tests/firefox/testAwesomeBar/manifest.ini
   349     testing/mozmill/tests/firefox/testPreferences/manifest.ini
   350     testing/mozmill/tests/firefox/testPrivateBrowsing/manifest.ini
   351     testing/mozmill/tests/firefox/testSessionStore/manifest.ini
   352     testing/mozmill/tests/firefox/testTechnicalTools/manifest.ini
   353     testing/mozmill/tests/firefox/testToolbar/manifest.ini
   355 The top-level `manifest.ini` merely has `[include:]` references to the sub manifests:
   357 .. code-block:: text
   359     [include:testAwesomeBar/manifest.ini]
   360     [include:testPreferences/manifest.ini]
   361     [include:testPrivateBrowsing/manifest.ini]
   362     [include:testSessionStore/manifest.ini]
   363     [include:testTechnicalTools/manifest.ini]
   364     [include:testToolbar/manifest.ini]
   366 Each sub-level manifest contains the (`.js`) test files relative to it.
   368 Updating the tests from manifests
   369 `````````````````````````````````
   371 You may need to update tests as given in manifests from a different source directory.
   372 `manifestparser update` was made for just this purpose:
   374 .. code-block:: text
   376     Usage: manifestparser [options] update manifest directory -tag1 -tag2 `key1=value1 --key2=value2 ...
   378         update the tests as listed in a manifest from a directory
   380 To update from a directory of tests in `~/mozmill/src/mozmill-tests/firefox/` run:
   382 .. code-block:: text
   384     manifestparser update manifest.ini ~/mozmill/src/mozmill-tests/firefox/
   386 Tests
   387 `````
   389 ManifestDestiny includes a suite of tests:
   391 https://github.com/mozilla/mozbase/tree/master/manifestdestiny/tests
   393 `test_manifest.txt` is a doctest that may be helpful in figuring out
   394 how to use the API.  Tests are run via `python test.py`.
   396 Bugs
   397 ````
   399 Please file any bugs or feature requests at
   401 https://bugzilla.mozilla.org/enter_bug.cgi?product=Testing&component=ManifestParser
   403 Or contact jhammel @mozilla.org or in #ateam on irc.mozilla.org
   405 CLI
   406 ```
   408 Run `manifestparser help` for usage information.
   410 To create a manifest from a set of directories:
   412 .. code-block:: text
   414     manifestparser [options] create directory <directory> <...> [create-options]
   416 To output a manifest of tests:
   418 .. code-block:: text
   420     manifestparser [options] write manifest <manifest> <...> -tag1 -tag2 --key1=value1 --key2=value2 ...
   422 To copy tests and manifests from a source:
   424 .. code-block:: text
   426     manifestparser [options] copy from_manifest to_manifest -tag1 -tag2 `key1=value1 key2=value2 ...
   428 To update the tests associated with with a manifest from a source
   429 directory:
   431 .. code-block:: text
   433     manifestparser [options] update manifest from_directory -tag1 -tag2 --key1=value1 --key2=value2 ...
   435 Design Considerations
   436 `````````````````````
   438 Contrary to some opinion, manifestparser.py and the associated .ini
   439 format were not magically plucked from the sky but were descended upon
   440 through several design considerations.
   442 * test manifests should be ordered.  While python 2.6 and greater has
   443   a ConfigParser that can use an ordered dictionary, it is a
   444   requirement that we support python 2.4 for the build + testing
   445   environment.  To that end, a `read_ini` function was implemented
   446   in manifestparser.py that should be the equivalent of the .ini
   447   dialect used by ConfigParser.
   449 * the manifest format should be easily human readable/writable.  While
   450   there was initially some thought of using JSON, there was pushback
   451   that JSON was not easily editable.  An ideal manifest format would
   452   degenerate to a line-separated list of files.  While .ini format
   453   requires an additional `[]` per line, and while there have been
   454   complaints about this, hopefully this is good enough.
   456 * python does not have an in-built YAML parser.  Since it was
   457   undesirable for manifestparser.py to have any dependencies, YAML was
   458   dismissed as a format.
   460 * we could have used a proprietary format but decided against it.
   461   Everyone knows .ini and there are good tools to deal with it.
   462   However, since read_ini is the only function that transforms a
   463   manifest to a list of key, value pairs, while the implications for
   464   changing the format impacts downstream code, doing so should be
   465   programmatically simple.
   467 * there should be a single file that may easily be
   468   transported. Traditionally, test harnesses have lived in
   469   mozilla-central. This is less true these days and it is increasingly
   470   likely that more tests will not live in mozilla-central going
   471   forward.  So `manifestparser.py` should be highly consumable. To
   472   this end, it is a single file, as appropriate to mozilla-central,
   473   which is also a working python package deployed to PyPI for easy
   474   installation.
   476 Historical Reference
   477 ````````````````````
   479 Date-ordered list of links about how manifests came to be where they are today::
   481 * https://wiki.mozilla.org/Auto-tools/Projects/UniversalManifest
   482 * http://alice.nodelman.net/blog/post/2010/05/
   483 * http://alice.nodelman.net/blog/post/universal-manifest-for-unit-tests-a-proposal/
   484 * https://elvis314.wordpress.com/2010/07/05/improving-personal-hygiene-by-adjusting-mochitests/
   485 * https://elvis314.wordpress.com/2010/07/27/types-of-data-we-care-about-in-a-manifest/
   486 * https://bugzilla.mozilla.org/show_bug.cgi?id=585106
   487 * http://elvis314.wordpress.com/2011/05/20/converting-xpcshell-from-listing-directories-to-a-manifest/
   488 * https://bugzilla.mozilla.org/show_bug.cgi?id=616999
   489 * https://developer.mozilla.org/en/Writing_xpcshell-based_unit_tests#Adding_your_tests_to_the_xpcshell_manifest

mercurial