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. +responses+ dictionary ~~~~~~~~~~~~~~~~~~~~~~ It contains dictionaries for 'GET', 'PUT', 'POST' and 'ALL'. All of them correspond to the method used by program. 'ALL' is just a shortcut that covers all methods and it is called only if no specific handler is found. Dictionaries associated with each method contains as a key relative URL to the top of the server and as data one of the following: * path to the file in fixtures directory with XML to return * XML itself starting with + Passed staging project "openSUSE:Factory:Staging:test" Passed staging project "openSUSE:Factory:Staging:test" test -------------------------------------------------------------------------------- [source,python] -------------------------------------------------------------------------------- # Getting template in test tmpl = Template(self._get_fixture_content('request_review.xml')) -------------------------------------------------------------------------------- Now prepare some default starting values [source,python] -------------------------------------------------------------------------------- # clear responses dictionary(just in case) self._clear_responses() # set default response self.responses['GET']['/request/123'] = tmpl.substitute(request='new', review='accepted', review_project="openSUSE:Factory") # register everything self._register_pretty() -------------------------------------------------------------------------------- Now the interesting part. Let's define a function, that would interpret 'POST' method, extract data from command and will actually change the response next 'GET' method will give. We can change the responses dictionary anytime, so we can use this to keep state once we get a command to do something. [source,python] -------------------------------------------------------------------------------- # Create function making transitions between states def review_change(responses, request, uri): if request.querystring.has_key(u'cmd') and request.querystring[u'cmd'] == [u'addreview']: responses['GET']['/request/123'] = tmpl.substitute(request='review', review='new', review_project=request.querystring[u'by_project'][0]) if request.querystring.has_key(u'cmd') and request.querystring[u'cmd'] == [u'changereviewstate']: responses['GET']['/request/123'] = tmpl.substitute(request='new', review=request.querystring[u'newstate'][0], review_project=request.querystring[u'by_project'][0]) return responses['GET']['/request/123'] # Register it self.responses['ALL']['/request/123'] = review_change -------------------------------------------------------------------------------- So whenever somebody sends 'addreview' command, XML that 'GET' on request provides will be changed to reflect newly added review. And whenever somebody sends 'changereviewstate', review will be closed with appropriate state. So we have a simple testing framework with multiple states that reacts to the API calls from functions we are testing following the behaviour we specified. So tests itself can be simple. [source,python] -------------------------------------------------------------------------------- # Add first review, there is none at beginning api.add_review('123', 'openSUSE:Factory:Staging:A') self.assertEqual(httpretty.last_request().method, 'POST') self.assertEqual(httpretty.last_request().querystring[u'cmd'], [u'addreview']) # Try to add it again, should do anything api.add_review('123', 'openSUSE:Factory:Staging:A') self.assertEqual(httpretty.last_request().method, 'GET') # Accept review api.set_review('123', 'openSUSE:Factory:Staging:A') self.assertEqual(httpretty.last_request().method, 'POST') self.assertEqual(httpretty.last_request().querystring[u'cmd'], [u'changereviewstate']) # Try to accept it again should do anything api.set_review('123', 'openSUSE:Factory:Staging:A') self.assertEqual(httpretty.last_request().method, 'GET') # But we should be able to create a new one api.add_review('123', 'openSUSE:Factory:Staging:A') self.assertEqual(httpretty.last_request().method, 'POST') self.assertEqual(httpretty.last_request().querystring[u'cmd'], [u'addreview']) --------------------------------------------------------------------------------