2014-02-05 17:09:05 +01:00
|
|
|
Testing
|
|
|
|
=======
|
|
|
|
|
|
|
|
Dependencies
|
|
|
|
------------
|
|
|
|
|
2014-02-06 11:14:08 +01:00
|
|
|
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:
|
2014-02-05 17:09:05 +01:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2014-02-06 11:14:08 +01:00
|
|
|
zypper in python-nose python-httpretty python-mock
|
2014-02-05 17:09:05 +01:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Running tests
|
|
|
|
-------------
|
|
|
|
|
|
|
|
To run the tests, you need to be in the topmost directory of your checkout and
|
|
|
|
run the following command there:
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
nosetests
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
2014-02-06 11:14:08 +01:00
|
|
|
Structure of the suite
|
|
|
|
----------------------
|
2014-02-05 17:09:05 +01:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2014-02-20 09:23:50 +01:00
|
|
|
Writing tests
|
|
|
|
-------------
|
|
|
|
|
|
|
|
There are few nice building stones available to implement test.
|
|
|
|
|
2014-02-24 16:27:28 +01:00
|
|
|
OBS class
|
|
|
|
~~~~~~~~~
|
|
|
|
|
|
|
|
+OBS+ class provides simulation of OBS including keeping internal states. It
|
|
|
|
supports only limited number of command, but that can be extended.
|
|
|
|
|
2014-06-11 18:20:38 +02:00
|
|
|
Extending OBS class
|
|
|
|
^^^^^^^^^^^^^^^^^^^
|
2014-02-20 09:23:50 +01:00
|
|
|
|
2014-06-11 18:20:38 +02:00
|
|
|
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.
|
2014-02-20 09:23:50 +01:00
|
|
|
|
2014-06-11 18:20:38 +02:00
|
|
|
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.
|
2014-02-20 09:23:50 +01:00
|
|
|
|
2014-06-11 18:20:38 +02:00
|
|
|
Because we are decorating methods, we can maintain an internal status
|
|
|
|
inside the OBS mock-up instance.
|
2014-02-20 09:23:50 +01:00
|
|
|
|
|
|
|
example
|
2014-02-24 16:27:28 +01:00
|
|
|
^^^^^^^
|
2014-02-20 09:23:50 +01:00
|
|
|
|
2014-02-24 16:27:28 +01:00
|
|
|
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.
|
2014-02-20 09:23:50 +01:00
|
|
|
|
|
|
|
.Template
|
|
|
|
[source,xml]
|
|
|
|
--------------------------------------------------------------------------------
|
2014-02-24 16:27:28 +01:00
|
|
|
<request id="${id}">
|
2014-02-20 09:23:50 +01:00
|
|
|
<action type="submit">
|
2014-02-24 16:27:28 +01:00
|
|
|
<source project="home:Admin" package="${package}" rev="59f0f46262d7b57b9cdc720c06d5e317"/>
|
|
|
|
<target project="openSUSE:Factory" package="${package}"/>
|
2014-02-20 09:23:50 +01:00
|
|
|
</action>
|
|
|
|
<state name="${request}" who="Admin" when="2014-02-17T12:38:52">
|
2014-02-24 16:27:28 +01:00
|
|
|
<comment>...</comment>
|
2014-02-20 09:23:50 +01:00
|
|
|
</state>
|
2014-02-24 16:27:28 +01:00
|
|
|
<review state="${review}" when="2014-02-17T12:34:10" who="${who}" by_${by}="${by_who}">
|
|
|
|
<comment>...</comment>
|
2014-02-20 09:23:50 +01:00
|
|
|
</review>
|
|
|
|
<description>test</description>
|
|
|
|
</request>
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
2014-02-24 16:27:28 +01:00
|
|
|
We can also define helpful local data structure representing actual state of OBS
|
2014-02-20 09:23:50 +01:00
|
|
|
|
|
|
|
[source,python]
|
|
|
|
--------------------------------------------------------------------------------
|
2014-02-24 16:27:28 +01:00
|
|
|
# Initial request data
|
2014-06-11 18:20:38 +02:00
|
|
|
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',
|
|
|
|
},
|
|
|
|
}
|
2014-02-20 09:23:50 +01:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
2014-02-24 16:27:28 +01:00
|
|
|
And the most important part is implementing OBS behaviour.
|
2014-02-20 09:23:50 +01:00
|
|
|
|
|
|
|
[source,python]
|
|
|
|
--------------------------------------------------------------------------------
|
2014-06-11 18:20:38 +02:00
|
|
|
@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
|
2014-02-20 09:23:50 +01:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
2014-06-11 18:20:38 +02:00
|
|
|
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.
|