From Fedora Project Wiki

m (add qa header)
(write up README, hook.py, and testlist)
Line 18: Line 18:


== README ==
== README ==
This is the human-readable description for this hook. It describes the event, the required and optional arguments that will be passed to autoqa and the tests, and any special argument processing or test filtering that might happen.
Here's an example, the <code>post-repo-update</code> README:
<pre>
This hook is for tests that run after a repo has changed. A repo is considered
"changed" if its package contents and metadata have been changed in some way.
The required argument for autoqa is a yum-compatible URL (probably http) that
points to the changed repo.
Some tests (e.g. repoclosure) need a list of "parent" repos to run properly.
You can specify these by doing '--parent URL1 --parent URL2 ...'
Any instances of '%a' in the URLs will be replaced by one of the listed
arches when the tests are actually run.
</pre>
Every hook has at least one required argument - usually a URL that points to the new package/tree/repo/whatever. It can also define one or more optional arguments, which will be handled by autoqa commandline arguments. Those get defined in hook.py.
== hook.py ==
== hook.py ==
This contains python code that will be loaded by autoqa when it is launched by the watcher. This code handles parsing the autoqa arguments, generating the data to be passed to the test, and filtering the list of tests, if needed. It must contain three functions: <code>extend_parser</code>, <code>process_testdata</code>, and <code>process_testlist</code>.
=== extend_parser() ===
This function is required. It is used to add hook-specific options to the given [http://docs.python.org/library/optparse.html OptionParser object], so autoqa can properly parse the arguments given by the watcher. Here's the <code>extend_parser()</code> from <code>post-repo-update</code>:
<pre>
import optparse
def extend_parser(parser):
    '''Extend the given OptionParser object with settings for this hook.'''
    parser.set_usage('%%prog %s [options] REPOURL' % name)
    group = optparse.OptionGroup(parser, '%s options' % name)
    group.add_option('-n', '--name', default='',
        help='Short, human-readable name for the repo under test')
    group.add_option('-p', '--parent', action='append', default=[],
        help='URL of a "parent" repo that this repo depends on for closure')
    parser.add_option_group(group)
    return parser
</pre>
The new options are generally used to handle the ''optional'' arguments to the test. This is where we've defined the <code>--parent</code> argument that the README mentioned.
The required argument(s) are handled in <code>process_testdata()</code>.
=== process_testdata() ===
This function is also required. It generates a dict of testdata - the key=value data that will be passed along to the test.
It uses the results of <code>parser.parse_args()</code> - <code>opts</code> contains the options, and <code>args</code> contains the list of unhandled (usually required) args. It also gets the requested test <code>arch</code>. (In the future it may get some extra keyword arguments, so it is usually defined with an **extra parameter.)
Here's the one from <code>post-repo-update</code>:
<pre>
def process_testdata(opts, args, arch, **extra):
    testdata = {'url': args[0].replace('%a', arch),
                'parents': ' '.join(opts.parent).replace('%a', arch)}
    if opts.name:
        testdata['reponame'] = '%s-%s' % (opts.name, arch)
    else:
        testdata['reponame'] = testdata['url']
    return testdata
</pre>
As you can see, it sets three values - The required argument is a URL, so we set <code>url</code> to the first non-option argument. <code>parents</code> is set to a space-separated list of the given <code>--parent</code> items. And <code>reponame</code> is set to the <code>--name</code> argument if given - otherwise we just use the URL, which is a nice unique identifier.
=== process_testlist() ===
Finally we have <code>process_testlist()</code>. This function takes the list of known tests for this hook (see testlist below) and filters out anything that might not be appropriate for the given arguments. It returns the modified list of tests.
In its simplest form, this function can just be defined as follows:
<pre>
def process_testlist(opts, args, testlist):
    return testlist
</pre>
Here's the version used by <code>post-repo-update</code>:
<pre>
def process_testlist(opts, args, testlist):
    if not opts.name.lower().startswith('rawhide'):
        if 'rats_sanity' in testlist:
            testlist.remove('rats_sanity')
    return testlist
</pre>
The <code>rats_sanity</code> test is only appropriate to run on [[Rawhide]] repos, so if the repo isn't named <code>rawhide</code>-something, we remove it from the list.
== templates ==
'''TODO'''
== testlist ==
== testlist ==
== templates ==
 
This file simply lists the names of tests that should be run for this hook. These names must correspond to directories in <code>tests/</code> that contain <code>control</code> files.
 
== Watcher ==
== Watcher ==
'''TODO'''


[[Category:AutoQA]]
[[Category:AutoQA]]

Revision as of 20:39, 26 August 2009

QA.png


Warning.png
This page is a draft only
It is still under construction and content may change. Do not rely on the information on this page.

Overview

The hooks/ directory in the autoqa source tree contains the hooks that AutoQA knows about. A hook has five main parts:

  1. README
    • describes the event itself and the required (and optional) arguments that will be passed along to the tests.
  2. hook.py
    • python code that is used to parse the test arguments, as described in the README file. This is the formal definition of the test arguments.
  3. testlist
    • contains the list of test names that will be launched when this hook is triggered.
  4. control.template and test_class_template.py
    • generic templates for creating new tests that use this hook. See below for more information on writing new tests.
  5. Watcher
    • This is the code that watches for the event and launches the autoqa harness with the arguments described in README and hook.py.
    • Currently, all existing watchers are scripts that get run periodically by crond to check to see if the event has occurred since the last time it was run. If so, it launches autoqa.
    • In the future this will change to a daemon that waits for notifications about the event - see the Messaging SIG's Publish Subscribe Notification Proposal for further info about that.

README

This is the human-readable description for this hook. It describes the event, the required and optional arguments that will be passed to autoqa and the tests, and any special argument processing or test filtering that might happen.

Here's an example, the post-repo-update README:

This hook is for tests that run after a repo has changed. A repo is considered
"changed" if its package contents and metadata have been changed in some way.

The required argument for autoqa is a yum-compatible URL (probably http) that
points to the changed repo.

Some tests (e.g. repoclosure) need a list of "parent" repos to run properly.
You can specify these by doing '--parent URL1 --parent URL2 ...'

Any instances of '%a' in the URLs will be replaced by one of the listed
arches when the tests are actually run.

Every hook has at least one required argument - usually a URL that points to the new package/tree/repo/whatever. It can also define one or more optional arguments, which will be handled by autoqa commandline arguments. Those get defined in hook.py.

hook.py

This contains python code that will be loaded by autoqa when it is launched by the watcher. This code handles parsing the autoqa arguments, generating the data to be passed to the test, and filtering the list of tests, if needed. It must contain three functions: extend_parser, process_testdata, and process_testlist.

extend_parser()

This function is required. It is used to add hook-specific options to the given OptionParser object, so autoqa can properly parse the arguments given by the watcher. Here's the extend_parser() from post-repo-update:

import optparse

def extend_parser(parser):
    '''Extend the given OptionParser object with settings for this hook.'''
    parser.set_usage('%%prog %s [options] REPOURL' % name)
    group = optparse.OptionGroup(parser, '%s options' % name)
    group.add_option('-n', '--name', default='',
        help='Short, human-readable name for the repo under test')
    group.add_option('-p', '--parent', action='append', default=[],
        help='URL of a "parent" repo that this repo depends on for closure')
    parser.add_option_group(group)
    return parser

The new options are generally used to handle the optional arguments to the test. This is where we've defined the --parent argument that the README mentioned.

The required argument(s) are handled in process_testdata().

process_testdata()

This function is also required. It generates a dict of testdata - the key=value data that will be passed along to the test.

It uses the results of parser.parse_args() - opts contains the options, and args contains the list of unhandled (usually required) args. It also gets the requested test arch. (In the future it may get some extra keyword arguments, so it is usually defined with an **extra parameter.)

Here's the one from post-repo-update:

def process_testdata(opts, args, arch, **extra):
    testdata = {'url': args[0].replace('%a', arch),
                'parents': ' '.join(opts.parent).replace('%a', arch)}
    if opts.name:
        testdata['reponame'] = '%s-%s' % (opts.name, arch)
    else:
        testdata['reponame'] = testdata['url']
    return testdata

As you can see, it sets three values - The required argument is a URL, so we set url to the first non-option argument. parents is set to a space-separated list of the given --parent items. And reponame is set to the --name argument if given - otherwise we just use the URL, which is a nice unique identifier.

process_testlist()

Finally we have process_testlist(). This function takes the list of known tests for this hook (see testlist below) and filters out anything that might not be appropriate for the given arguments. It returns the modified list of tests.

In its simplest form, this function can just be defined as follows:

def process_testlist(opts, args, testlist):
    return testlist

Here's the version used by post-repo-update:

def process_testlist(opts, args, testlist):
    if not opts.name.lower().startswith('rawhide'):
        if 'rats_sanity' in testlist:
            testlist.remove('rats_sanity')
    return testlist

The rats_sanity test is only appropriate to run on Rawhide repos, so if the repo isn't named rawhide-something, we remove it from the list.

templates

TODO

testlist

This file simply lists the names of tests that should be run for this hook. These names must correspond to directories in tests/ that contain control files.

Watcher

TODO