diff --git a/tests/api_tests.py b/tests/api_tests.py
index 0daf051b..30656ded 100644
--- a/tests/api_tests.py
+++ b/tests/api_tests.py
@@ -32,17 +32,31 @@ if PY3:
else:
string_types = basestring,
-class TestApiCalls(unittest.TestCase):
+class OBS:
"""
- Tests for various api calls to ensure we return expected content
+ Class trying to simulate a simple OBS
"""
- responses = { 'GET': {}, 'PUT': {}, 'POST': {}, 'ALL': {} }
+ responses = { }
+
+ def __init__(self):
+ """
+ Initialize the configuration and create basic OBS instance
+ """
+
+ self.reset_config()
+
+ def reset_config(self):
+ self._clear_responses()
def _clear_responses(self):
"""
Reset predefined responses
"""
self.responses = { 'GET': {}, 'PUT': {}, 'POST': {}, 'ALL': {} }
+ # Add methods to manipulate reviews
+ self._request_review()
+ # Add methods to search requests
+ self._request_search()
def _pretty_callback(self, request, uri, headers):
"""
@@ -55,31 +69,147 @@ class TestApiCalls(unittest.TestCase):
:param uri: uri as provided to callback function by HTTPretty
:param headers: headers as provided to callback function by HTTPretty
"""
+
+ # Get path
path = re.match( r'.*localhost([^?]*)(\?.*)?',uri).group(1)
reply = None
+ # Try to find a fallback
if self.responses['ALL'].has_key(path):
reply = self.responses['ALL'][path]
+ # Try to find a specific method
if self.responses[request.method].has_key(path):
reply = self.responses[request.method][path]
+ # We have something to reply with
if reply:
+ # It's a list, so take the first
if isinstance(reply, list):
reply = reply.pop(0)
+ # It's string
if isinstance(reply, string_types):
- return (200, headers, reply)
+ # It's XML
+ if reply.startswith('<'):
+ return (200, headers, reply)
+ # It's fixture
+ else:
+ return (200, headers, _get_fixture_content(reply))
+ # All is left is callback function
else:
return (200, headers, reply(self.responses, request, uri))
+ # No possible response found
else:
if len(path) == 0:
path = uri
raise BaseException("No response for {0} on {1} provided".format(request.method,path))
- def _register_pretty(self):
+ # Initial request data
+ requests_data = { '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' }
+ }
+
+ def _request_review(self):
+ """
+ Register requests methods
+ """
+
+ # Load template
+ tmpl = Template(self._get_fixture_content('request_review.xml'))
+
+ # What happens when we try to change the review
+ def review_change(responses, request, uri):
+ rq_id = re.match( r'.*/([0-9]+)',uri).group(1)
+ args = self.requests_data[rq_id]
+ # Adding review
+ if request.querystring.has_key(u'cmd') and request.querystring[u'cmd'] == [u'addreview']:
+ self.requests_data[rq_id]['request'] = 'review'
+ self.requests_data[rq_id]['review'] = 'new'
+ # Changing review
+ if request.querystring.has_key(u'cmd') and request.querystring[u'cmd'] == [u'changereviewstate']:
+ self.requests_data[rq_id]['request'] = 'new'
+ self.requests_data[rq_id]['review'] = request.querystring[u'newstate'][0]
+ # Project review
+ if request.querystring.has_key(u'by_project'):
+ self.requests_data[rq_id]['by'] = 'project'
+ self.requests_data[rq_id]['by_who'] = request.querystring[u'by_project'][0]
+ # Group review
+ if request.querystring.has_key(u'by_group'):
+ self.requests_data[rq_id]['by'] = 'group'
+ self.requests_data[rq_id]['by_who'] = request.querystring[u'by_group'][0]
+ responses['GET']['/request/' + rq_id] = tmpl.substitute(self.requests_data[rq_id])
+ return responses['GET']['/request/' + rq_id]
+
+ # Register methods for all requests
+ for rq in self.requests_data:
+ self.responses['GET']['/request/' + rq] = tmpl.substitute(self.requests_data[rq])
+ self.responses['ALL']['/request/' + rq] = review_change
+
+ def _request_search(self):
+ """
+ Allows searching for requests
+ """
+ def request_search(responses, request, uri):
+ # Searching for requests that has open review for staging group
+ if request.querystring.has_key(u'match') and request.querystring[u'match'][0] == u"state/@name='review' and review[@by_group='factory-staging' and @state='new']":
+ rqs = []
+ # Itereate through all requests
+ for rq in self.requests_data:
+ # Find the ones matching the condition
+ if self.requests_data[rq]['request'] == 'review' and self.requests_data[rq]['review'] == 'new' and self.requests_data[rq]['by'] == 'group' and self.requests_data[rq]['by_who'] == 'factory-staging':
+ rqs.append(rq)
+ # Create response
+ ret_str = ''
+ for rq in rqs:
+ ret_str += responses['GET']['/request/' + rq]
+ ret_str += ''
+ return ret_str
+ # We are searching for something else, we don't know the answer
+ raise BaseException("No search results defined for " + pprint.pformat(request.querystring))
+ self.responses['GET']['/search/request'] = request_search
+
+ def register_obs(self):
"""
Register custom callback for HTTPretty
"""
httpretty.register_uri(httpretty.GET,re.compile(r'/.*localhost.*/'),body=self._pretty_callback)
httpretty.register_uri(httpretty.PUT,re.compile(r'/.*localhost.*/'),body=self._pretty_callback)
httpretty.register_uri(httpretty.POST,re.compile(r'/.*localhost.*/'),body=self._pretty_callback)
+ self.reset_config()
+ # Initiate the api with mocked rings
+ with mock_generate_ring_packages():
+ self.api = oscs.StagingAPI('http://localhost')
+
+ def _get_fixtures_dir(self):
+ """
+ Return path for fixtures
+ """
+ return os.path.join(os.getcwd(), 'tests/fixtures')
+
+ def _get_fixture_path(self, filename):
+ """
+ Return path for fixture
+ """
+ return os.path.join(self._get_fixtures_dir(), filename)
+
+ def _get_fixture_content(self, filename):
+ """
+ Return content of fixture
+ """
+ response = open(self._get_fixture_path(filename), 'r')
+ content = response.read()
+ response.close()
+ return content
+
+class TestApiCalls(unittest.TestCase):
+ """
+ Tests for various api calls to ensure we return expected content
+ """
+
+ obs = OBS()
def _get_fixtures_dir(self):
"""
@@ -165,22 +295,17 @@ class TestApiCalls(unittest.TestCase):
Test dispatching and closure of non-ring packages
"""
- # Initiate the pretty overrides
- self._register_pretty_url_get('http://localhost/search/request?match=state/@name=\'review\'+and+review[@by_group=\'factory-staging\'+and+@state=\'new\']',
- 'open-requests.xml')
-
- # There should be just one request that gets closed
- # We don't care about the return so just reuse the above :P
- # If there is bug in the function we get assertion about closing more issues than we should
- self._register_pretty_url_post('http://localhost/request/220956?comment=No+need+for+staging%2C+not+in+tested+ring+project.&newstate=accepted&by_group=factory-staging&cmd=changereviewstate',
- 'open-requests.xml')
-
- # Initiate the api with mocked rings
- with mock_generate_ring_packages():
- api = oscs.StagingAPI('http://localhost')
-
- # get the open requests
- requests = api.dispatch_open_requests()
+ # Register OBS
+ self.obs.register_obs()
+ # Get rid of open requests
+ self.obs.api.dispatch_open_requests()
+ # Check that we tried to close it
+ self.assertEqual(httpretty.last_request().method, 'POST')
+ self.assertEqual(httpretty.last_request().querystring[u'cmd'], [u'changereviewstate'])
+ # Try it again
+ self.obs.api.dispatch_open_requests()
+ # This time there should be nothing to close
+ self.assertEqual(httpretty.last_request().method, 'GET')
@httpretty.activate
def test_pseudometa_get_prj(self):
@@ -306,41 +431,25 @@ class TestApiCalls(unittest.TestCase):
Test whether accepting/creating reviews behaves correctly
"""
- with mock_generate_ring_packages():
- api = oscs.StagingAPI('http://localhost')
-
- tmpl = Template(self._get_fixture_content('request_review.xml'))
-
- self._clear_responses()
- self.responses['GET']['/request/123'] = tmpl.substitute(request='new', review='accepted', review_project="openSUSE:Factory")
-
- 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']
-
- self.responses['ALL']['/request/123'] = review_change
-
- self._register_pretty()
+ # Register OBS
+ self.obs.register_obs()
# Add review
- api.add_review('123', 'openSUSE:Factory:Staging:A')
+ self.obs.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 readd, should do anything
- api.add_review('123', 'openSUSE:Factory:Staging:A')
+ self.obs.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.obs.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.obs.api.set_review('123', 'openSUSE:Factory:Staging:A')
self.assertEqual(httpretty.last_request().method, 'GET')
# But we should be able to reopen it
- api.add_review('123', 'openSUSE:Factory:Staging:A')
+ self.obs.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'])
diff --git a/tests/fixtures/open-requests.xml b/tests/fixtures/open-requests.xml
deleted file mode 100644
index 90133c4b..00000000
--- a/tests/fixtures/open-requests.xml
+++ /dev/null
@@ -1,255 +0,0 @@
-
-
-
-
-
-
-
- Check Staging Project
-
-
- {"approve": "preliminary, version number changed"} <!-- {
- "dest": {
- "ldb": {
- "prodonly": "",
- "review": "done",
- "rpm_license": "{\"python3.spec\":{\"curses\":[\"Python-2.0\"],\"python3\":[\"Python-2.0\"],\"dbm\":[\"Python-2.0\"],\"tk\":[\"Python-2.0\"]},\"python3-base.spec\":{\"-n python3-tools\":[\"Python-2.0\"],\"-n python3-idle\":[\"Python-2.0\"],\"python3-base\":[\"Python-2.0\"],\"-n python3-testsuite\":[\"Python-2.0\"],\"-n libpython%{so_version}\":[\"Python-2.0\"],\"-n python3-devel\":[\"Python-2.0\"]},\"python3-doc.spec\":{\"python3-doc\":[\"Python-2.0\"],\"pdf\":[\"Python-2.0\"]}}",
- "status": "production",
- "version": "3.3.3"
- },
- "license": {
- "python3-base.spec": {
- "-n libpython%{so_version}": [
- "Python-2.0"
- ],
- "-n python3-devel": [
- "Python-2.0"
- ],
- "-n python3-idle": [
- "Python-2.0"
- ],
- "-n python3-testsuite": [
- "Python-2.0"
- ],
- "-n python3-tools": [
- "Python-2.0"
- ],
- "python3-base": [
- "Python-2.0"
- ]
- },
- "python3-doc.spec": {
- "pdf": [
- "Python-2.0"
- ],
- "python3-doc": [
- "Python-2.0"
- ]
- },
- "python3.spec": {
- "curses": [
- "Python-2.0"
- ],
- "dbm": [
- "Python-2.0"
- ],
- "python3": [
- "Python-2.0"
- ],
- "tk": [
- "Python-2.0"
- ]
- }
- },
- "version": "3.3.3"
- },
- "hint": [
- "version changed: src('3.3.3') differs from dest('3.4.0~b3')"
- ],
- "plugin": "0.60",
- "src": {
- "auto-co": "/api.opensuse.org/devel:languages:python:Factory/python3%3.4.0~b3%r125",
- "kiwi_only": false,
- "license": {
- "python3-base.spec": {
- "-n libpython%{so_version}": [
- "Python-2.0"
- ],
- "-n python3-devel": [
- "Python-2.0"
- ],
- "-n python3-idle": [
- "Python-2.0"
- ],
- "-n python3-testsuite": [
- "Python-2.0"
- ],
- "-n python3-tools": [
- "Python-2.0"
- ],
- "python3-base": [
- "Python-2.0"
- ]
- },
- "python3-doc.spec": {
- "pdf": [
- "Python-2.0"
- ],
- "python3-doc": [
- "Python-2.0"
- ]
- },
- "python3.spec": {
- "curses": [
- "Python-2.0"
- ],
- "dbm": [
- "Python-2.0"
- ],
- "python3": [
- "Python-2.0"
- ],
- "tk": [
- "Python-2.0"
- ]
- }
- },
- "rev": "125",
- "version": "3.4.0~b3",
- "version_diff": "src('3.3.3') differs from dest('3.4.0~b3')"
- }
-} -->
-
-
- Check script succeeded
-
-
- ok
-
-
- Builds for repo openSUSE_Factory
-
-
- Check Staging Project
-
-
-
- Please review sources
-
-
- Please review build success
-
- - initial commit of 3.4.0 beta 3
- * new stdlib modules: pathlib, enum, statistics, tracemalloc
- * asynchronous IO with new asyncio module
- * introspection data for builtins
- * subprocesses no longer inherit open file descriptors
- * standardized metadata for packages
- * internal hashing changed to SipHash
- * new pickle protocol
- * improved handling of codecs
- * TLS 1.2 support
- * major speed improvements for internal unicode handling
- * many bugfixes and optimizations
-- see porting guide at:
- http://docs.python.org/3.4/whatsnew/3.4.html#porting-to-python-3-4
-- moved several modules to -testsuite subpackage
-- updated list of binary extensions, refreshed patches
-- tracemalloc_gcov.patch fixes profile-based optimization build
-- updated packages and pre_checkin.sh to use ~-version notation
- for prereleases
-- fix-shebangs part of build process moved to common %prep
-- drop python-3.3.2-no-REUSEPORT.patch (upstreamed)
-- update baselibs for new soname
-- TODOs:
- * require python-pip, make ensurepip work with zypper
-
-- initial commit of 3.4.0 beta2
- * for full changelog, see python3-base
-
-- initial commit of 3.4.0 beta 3
- * for full changelog, see python3-base
-
-
-
-
-
-
-
- Check Staging Project
-
-
- {"approve": "preliminary, version number changed"} <!-- {
- "dest": {
- "ldb": {
- "review": "never",
- "rpm_license": "{\"xf86-video-intel.spec\":{\"xf86-video-intel\":[\"MIT\"]}}",
- "status": "production",
- "version": "2.99.909"
- },
- "license": {
- "xf86-video-intel.spec": {
- "xf86-video-intel": [
- "MIT"
- ]
- }
- },
- "version": "2.99.909"
- },
- "hint": [
- "no ldb.risk defined, okay as per bnc#771677. ",
- "ldb.review was (apparently) never done"
- ],
- "plugin": "0.60",
- "src": {
- "auto-co": "/api.opensuse.org/X11:XOrg/xf86-video-intel%2.99.910%r110",
- "kiwi_only": false,
- "license": {
- "xf86-video-intel.spec": {
- "xf86-video-intel": [
- "MIT"
- ]
- }
- },
- "rev": "110",
- "version": "2.99.910",
- "version_diff": null
- }
-} -->
-
-
- Check script succeeded
-
-
- Please review sources
-
-
- Please review build success
-
-
- Check Staging Project
-
-
-
- Please review sources
-
-
- Please review build success
-
- - Update to 3.0 prerelease 2.99.910
- * Only discard damage when overwriting the dirty CPU bo, instead
- of discarding damage that will be shown!
- * Reset operation state when switching between glyph caches.
- https://bugs.freedesktop.org/show_bug.cgi?id=74494
- * Fully reinitialise pixmaps allocated from the freed cache. Fixes
- a potential issue (crash or misrendering) when using some compositors.
- https://bugs.freedesktop.org/show_bug.cgi?id=74550
- * Do not expose the TexturedVideo adaptor in UXA when it is disabled
- either due to a hung GPU or explicitly disabled by the user.
- * Restore the pipe stall when changing CC state on gen6, otherwise
- the GPU may not flush intermediate results from all EU resulting
- in render corruption (usually the occasional black box).
- Regression from 2.99.906
- https://bugs.freedesktop.org/show_bug.cgi?id=7237
-
-
diff --git a/tests/fixtures/request_review.xml b/tests/fixtures/request_review.xml
index 21360bfc..e774c24b 100644
--- a/tests/fixtures/request_review.xml
+++ b/tests/fixtures/request_review.xml
@@ -1,14 +1,13 @@
-
-
+
-
-
+
+
- Passed staging project "openSUSE:Factory:Staging:test"
+ ...
-
- Passed staging project "openSUSE:Factory:Staging:test"
+
+ ...
test