From Fedora Project Wiki

(updated for new_koji_watcher changes)
(Edited due to hook split in the event/watcher)
Line 3: Line 3:
  
 
== Overview ==
 
== Overview ==
The {{filename|hooks/}} directory in the <code>autoqa</code> source tree contains the hooks that AutoQA knows about. A hook has these main parts:
+
The {{filename|events/}} directory in the <code>autoqa</code> source tree contains the events that AutoQA knows about. Watchers for these events are stored within {{filename|watchers/}} directory.
  
 +
An event has these parts:
 
# {{filename|README}}
 
# {{filename|README}}
 
#* describes the event itself and the required (and optional) arguments that will be passed along to the tests.
 
#* describes the event itself and the required (and optional) arguments that will be passed along to the tests.
# {{filename|hook.py}}
+
# {{filename|event.py}}
 
#* python code that is used to parse the test arguments, as described in the {{filename|README}} file. This is the formal definition of the test arguments.
 
#* python code that is used to parse the test arguments, as described in the {{filename|README}} file. This is the formal definition of the test arguments.
# {{filename|watcher}}
+
 
#* This is the code that watches for the event and launches the <code>autoqa</code> harness with the arguments described in <code>README</code> and <code>hook.py</code>.
+
A watcher consists of:
 +
# {{filename|README}}
 +
#* describes the general area that the watcher monitors and lists all events that are triggered by it.
 +
# {{filename|watcher.py}}
 +
#* Is the code that watches for the event and launches the <code>autoqa</code> harness with the arguments described in <code>README</code> of an event and <code>event.py</code>.
 
#* Currently, most of the existing watchers are scripts that get run periodically by <code>crond</code> to check to see if the event has occurred since the last time it was run. If so, it launches <code>autoqa</code>.
 
#* Currently, most of the existing watchers are scripts that get run periodically by <code>crond</code> to check to see if the event has occurred since the last time it was run. If so, it launches <code>autoqa</code>.
 
#* 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.
 
#* 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.
#* The watcher script may be located in another hook's directory for some reason (e.g. code sharing). This is always documented in the {{filename|README}}.
+
#* In past, watchers and events were united into single "hooks". We have separated hooks in the watchers/event since it became clear that a single watcher can manage multiple different events.
  
== README ==
+
== Event 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.  
+
This is the human-readable description for this event. It describes it, 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:
 
Here's an example, the <code>post-repo-update</code> README:
 
<pre>
 
<pre>
This hook is for tests that run after a repo has changed. A repo is considered
+
This event 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.
 
"changed" if its package contents and metadata have been changed in some way.
  
Line 32: Line 37:
 
               specified multiple times
 
               specified multiple times
  
AutoQA tests can expect the following variables from post-repo-update hook:
+
AutoQA tests can expect the following variables from post-repo-update event:
 
   baseurl: url of repo that changed
 
   baseurl: url of repo that changed
 
   parents: list of urls for 'parent' repos of the given repo (may be empty)
 
   parents: list of urls for 'parent' repos of the given repo (may be empty)
Line 38: Line 43:
 
</pre>
 
</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.
+
Every event 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 event.py.
  
== hook.py ==
+
== event.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 and generating the data to be passed to the test. It must contain two methods: <code>extend_parser</code> and <code>process_testdata</code>.
 
This contains python code that will be loaded by autoqa when it is launched by the watcher. This code handles parsing the autoqa arguments and generating the data to be passed to the test. It must contain two methods: <code>extend_parser</code> and <code>process_testdata</code>.
Line 46: Line 51:
 
=== extend_parser() ===
 
=== extend_parser() ===
  
This function adds 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>:
+
This function adds event-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>
 
<pre>
Line 52: Line 57:
  
 
def extend_parser(parser):
 
def extend_parser(parser):
     '''Extend the given OptionParser object with settings for this hook.'''
+
     '''Extend the given OptionParser object with settings for this event.'''
 
     parser.set_usage('%%prog %s [options] REPOURL' % name)
 
     parser.set_usage('%%prog %s [options] REPOURL' % name)
 
     group = optparse.OptionGroup(parser, '%s options' % name)
 
     group = optparse.OptionGroup(parser, '%s options' % name)
Line 79: Line 84:
 
     '''Given an optparse.Values object and a list of args (as returned from
 
     '''Given an optparse.Values object and a list of args (as returned from
 
     OptionParser.parse_args()), return a dict containing the appropriate key=val
 
     OptionParser.parse_args()), return a dict containing the appropriate key=val
     pairs required by test's control files and test object. The hook can also
+
     pairs required by test's control files and test object. The event can also
 
     call parser.error here if it find out that not all options are correctly
 
     call parser.error here if it find out that not all options are correctly
 
     populated.'''
 
     populated.'''
Line 96: Line 101:
 
== Watcher ==
 
== Watcher ==
  
This is the heart of the hook: the part that actually watches for the event and triggers autoqa when it happens.  
+
The watcher is a program that actually watches for the event and triggers autoqa when it happens.  
  
The watcher is responsible for constructing the correct <code>autoqa</code> commandline (as defined in [[#README]] and [[#hook.py]], above) and executing <code>autoqa</code>. The rest of the design depends on the nature of the event.   
+
The watcher is responsible for constructing the correct <code>autoqa</code> commandline (as defined in [[#Event README]] and [[#event.py]], above) and executing <code>autoqa</code>. The rest of the design depends on the nature of the event.   
  
 
The current watchers for <code>post-repo-update</code> and <code>post-tree-compose</code> are run at regular intervals by <code>cron</code>. They check a certain file in each known repo ({{filename|repomd.xml}} or {{filename|.treeinfo}}, respectively) to see if it's different from the cached copy. If it's changed, they save the new file and launch <code>autoqa</code> for the repo/tree that has updated.
 
The current watchers for <code>post-repo-update</code> and <code>post-tree-compose</code> are run at regular intervals by <code>cron</code>. They check a certain file in each known repo ({{filename|repomd.xml}} or {{filename|.treeinfo}}, respectively) to see if it's different from the cached copy. If it's changed, they save the new file and launch <code>autoqa</code> for the repo/tree that has updated.
Line 104: Line 109:
 
Yours could work that way, or it could be a daemon that waits for a signal, or any other design that makes sense. A full discussion about how to write a watcher is outside the scope of this page, but you might get some inspiration by looking at the current watchers:
 
Yours could work that way, or it could be a daemon that waits for a signal, or any other design that makes sense. A full discussion about how to write a watcher is outside the scope of this page, but you might get some inspiration by looking at the current watchers:
  
* [https://fedorahosted.org/autoqa/browser/hooks/post-repo-update/watch-repos.py watch-repos.py]
+
* [https://fedorahosted.org/autoqa/browser/watchers/yum-repo/watcher.py watcher.py]
* [https://fedorahosted.org/autoqa/browser/hooks/post-tree-compose/watch-composes.py watch-composes.py]
+
* [https://fedorahosted.org/autoqa/browser/watchers/compose/watcher.py watcher.py]
* [https://fedorahosted.org/autoqa/browser/hooks/post-koji-build/watch-koji-builds.py watch-koji-builds.py]
+
* [https://fedorahosted.org/autoqa/browser/watchers/koji-bodhi/watcher.py watcher.py]
  
 
[[Category:AutoQA]]
 
[[Category:AutoQA]]

Revision as of 14:39, 28 March 2011

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 events/ directory in the autoqa source tree contains the events that AutoQA knows about. Watchers for these events are stored within watchers/ directory.

An event has these parts:

  1. README
    • describes the event itself and the required (and optional) arguments that will be passed along to the tests.
  2. event.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.

A watcher consists of:

  1. README
    • describes the general area that the watcher monitors and lists all events that are triggered by it.
  2. watcher.py
    • Is the code that watches for the event and launches the autoqa harness with the arguments described in README of an event and event.py.
    • Currently, most of the 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.
    • In past, watchers and events were united into single "hooks". We have separated hooks in the watchers/event since it became clear that a single watcher can manage multiple different events.

Event README

This is the human-readable description for this event. It describes it, 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 event 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.

Optional arguments:
    --name: human readable name for the repo under test
    --parent: a repo URL that is "parent" to the the repo under test; may be
              specified multiple times

AutoQA tests can expect the following variables from post-repo-update event:
  baseurl: url of repo that changed
  parents: list of urls for 'parent' repos of the given repo (may be empty)
  name: name for repo that changed (may be empty)

Every event 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 event.py.

event.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 and generating the data to be passed to the test. It must contain two methods: extend_parser and process_testdata.

extend_parser()

This function adds event-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 event.'''
    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 arguments are then handled in process_testdata().

process_testdata()

This function generates and returns 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. (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(parser, opts, args, **extra):
    '''Given an optparse.Values object and a list of args (as returned from
    OptionParser.parse_args()), return a dict containing the appropriate key=val
    pairs required by test's control files and test object. The event can also
    call parser.error here if it find out that not all options are correctly
    populated.'''

    if not args:
        parser.error('No repo URL was specified as a test argument!')

    testdata = {'baseurl': args[0],
                'parents': opts.parent,
                'name': opts.name or ''}
    return testdata

As you can see, it sets three values - The required argument is a URL, so we set baseurl to the first non-option argument. parents is set to a list of the given --parent items. And name is set to the --name argument if given - otherwise we just use empty string.

Watcher

The watcher is a program that actually watches for the event and triggers autoqa when it happens.

The watcher is responsible for constructing the correct autoqa commandline (as defined in #Event README and #event.py, above) and executing autoqa. The rest of the design depends on the nature of the event.

The current watchers for post-repo-update and post-tree-compose are run at regular intervals by cron. They check a certain file in each known repo (repomd.xml or .treeinfo, respectively) to see if it's different from the cached copy. If it's changed, they save the new file and launch autoqa for the repo/tree that has updated.

Yours could work that way, or it could be a daemon that waits for a signal, or any other design that makes sense. A full discussion about how to write a watcher is outside the scope of this page, but you might get some inspiration by looking at the current watchers: