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
To run the tests, you need to be in the topmost directory of your checkout and run the following command there:
nosetests
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.
There are few nice building stones available to implement test.
OBS
class provides simulation of OBS including keeping internal states. It
supports only limited number of command, but that can be extended.
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.
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.
<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.