Skip to content

Latest commit

 

History

History
136 lines (109 loc) · 4.25 KB

testing.asciidoc

File metadata and controls

136 lines (109 loc) · 4.25 KB

Testing

Dependencies

Test suite is using nose, httpretty and mock for testing. You need these three python modules installed to run tests. In openSUSE, you can do it using the following command as a root:

zypper in python-nose python-httpretty python-mock

Running tests

To run the tests, you need to be in the topmost directory of your checkout and run the following command there:

nosetests

Structure of the suite

Each object is containing functions for the individual tests so split them per area of interest.

In directory fixtures there are resulting xml files obtained from the OBS with osc api calls.

Writing tests

There are few nice building stones available to implement test.

OBS class

OBS class provides simulation of OBS including keeping internal states. It supports only limited number of command, but that can be extended.

Extending OBS class

You can extend the OBS mockup class creating new method, and decorating it with one of the @GET, @PUT, @POST or @DELETE. The parameter of the decorator is the PATH of the URL or a regular expression that match one of the possible paths.

If the new response can be implemented as a simple fixture, you can create the file in the fixtures/ directory in a place compatible in the expected path.

Because we are decorating methods, we can maintain an internal status inside the OBS mock-up instance.

example

First we create a template for our response. We will be using pythons string Template class therefore XML has some values replaced with ${variable} and we will assign those later.

Template
<request id="${id}">
  <action type="submit">
    <source project="home:Admin" package="${package}" rev="59f0f46262d7b57b9cdc720c06d5e317"/>
    <target project="openSUSE:Factory" package="${package}"/>
  </action>
  <state name="${request}" who="Admin" when="2014-02-17T12:38:52">
    <comment>...</comment>
  </state>
  <review state="${review}" when="2014-02-17T12:34:10" who="${who}" by_${by}="${by_who}">
    <comment>...</comment>
  </review>
  <description>test</description>
</request>

We can also define helpful local data structure representing actual state of OBS

# Initial request data
self.requests = {
    '123': {
        'request': 'new',
        'review': 'accepted',
        'who': 'Admin',
        'by': 'group',
        'id': '123',
        'by_who': 'opensuse-review-team',
        'package': 'gcc',
    },
    '321': {
        'request': 'review',
        'review': 'new',
        'who': 'Admin',
        'by': 'group',
        'id': '321',
        'by_who': 'factory-staging',
        'package': 'puppet',
    },
}

And the most important part is implementing OBS behaviour.

@GET(re.compile(r'/request/\d+'))
def request(self, request, uri, headers):
    """Return a request XML description."""
    request_id = re.search(r'(\d+)', uri).group(1)
    response = (404, headers, '<result>Not found</result>')
    try:
        template = string.Template(self._fixture(uri))
        response = (200, headers, template.substitute(self.requests[request_id]))
    except Exception as e:
        if DEBUG:
            print uri, e

    if DEBUG:
        print 'REQUEST', uri, response

    return response

The method request will be called when a request to /request/NUMBER is made. The previous code will load the XML template and replace variables with the request dictionary content.