root / snf-django-lib / snf_django / utils / testing.py @ dcb8545f
History | View | Annotate | Download (9.5 kB)
1 | f09da76e | Kostas Papadimitriou | # Copyright 2011-2013 GRNET S.A. All rights reserved.
|
---|---|---|---|
2 | f09da76e | Kostas Papadimitriou | #
|
3 | f09da76e | Kostas Papadimitriou | # Redistribution and use in source and binary forms, with or
|
4 | f09da76e | Kostas Papadimitriou | # without modification, are permitted provided that the following
|
5 | f09da76e | Kostas Papadimitriou | # conditions are met:
|
6 | f09da76e | Kostas Papadimitriou | #
|
7 | f09da76e | Kostas Papadimitriou | # 1. Redistributions of source code must retain the above
|
8 | f09da76e | Kostas Papadimitriou | # copyright notice, this list of conditions and the following
|
9 | f09da76e | Kostas Papadimitriou | # disclaimer.
|
10 | f09da76e | Kostas Papadimitriou | #
|
11 | f09da76e | Kostas Papadimitriou | # 2. Redistributions in binary form must reproduce the above
|
12 | f09da76e | Kostas Papadimitriou | # copyright notice, this list of conditions and the following
|
13 | f09da76e | Kostas Papadimitriou | # disclaimer in the documentation and/or other materials
|
14 | f09da76e | Kostas Papadimitriou | # provided with the distribution.
|
15 | f09da76e | Kostas Papadimitriou | #
|
16 | f09da76e | Kostas Papadimitriou | # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 | f09da76e | Kostas Papadimitriou | # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 | f09da76e | Kostas Papadimitriou | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 | f09da76e | Kostas Papadimitriou | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 | f09da76e | Kostas Papadimitriou | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 | f09da76e | Kostas Papadimitriou | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 | f09da76e | Kostas Papadimitriou | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 | f09da76e | Kostas Papadimitriou | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 | f09da76e | Kostas Papadimitriou | # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 | f09da76e | Kostas Papadimitriou | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 | f09da76e | Kostas Papadimitriou | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 | f09da76e | Kostas Papadimitriou | # POSSIBILITY OF SUCH DAMAGE.
|
28 | f09da76e | Kostas Papadimitriou | #
|
29 | f09da76e | Kostas Papadimitriou | # The views and conclusions contained in the software and
|
30 | f09da76e | Kostas Papadimitriou | # documentation are those of the authors and should not be
|
31 | f09da76e | Kostas Papadimitriou | # interpreted as representing official policies, either expressed
|
32 | f09da76e | Kostas Papadimitriou | # or implied, of GRNET S.A.
|
33 | f09da76e | Kostas Papadimitriou | |
34 | f09da76e | Kostas Papadimitriou | |
35 | f09da76e | Kostas Papadimitriou | from contextlib import contextmanager |
36 | d2b8ec7b | Christos Stavrakakis | from django.test import TestCase |
37 | d2b8ec7b | Christos Stavrakakis | from django.utils import simplejson as json |
38 | dcb8545f | Christos Stavrakakis | from synnefo.util import text |
39 | d2b8ec7b | Christos Stavrakakis | from mock import patch |
40 | f09da76e | Kostas Papadimitriou | |
41 | f09da76e | Kostas Papadimitriou | |
42 | f09da76e | Kostas Papadimitriou | @contextmanager
|
43 | f09da76e | Kostas Papadimitriou | def override_settings(settings, **kwargs): |
44 | f09da76e | Kostas Papadimitriou | """
|
45 | f09da76e | Kostas Papadimitriou | Helper context manager to override django settings within the provided
|
46 | f09da76e | Kostas Papadimitriou | context.
|
47 | f09da76e | Kostas Papadimitriou |
|
48 | f09da76e | Kostas Papadimitriou | All keyword arguments provided are set to the django settings object and
|
49 | f09da76e | Kostas Papadimitriou | get reverted/removed when the manager exits.
|
50 | f09da76e | Kostas Papadimitriou |
|
51 | f09da76e | Kostas Papadimitriou | >>> from synnefo.util.testing import override_settings
|
52 | f09da76e | Kostas Papadimitriou | >>> from django.conf import settings
|
53 | f09da76e | Kostas Papadimitriou | >>> with override_settings(settings, DEBUG=True):
|
54 | f09da76e | Kostas Papadimitriou | >>> assert settings.DEBUG == True
|
55 | f09da76e | Kostas Papadimitriou |
|
56 | f09da76e | Kostas Papadimitriou | The special arguemnt ``prefix`` can be set to prefix all setting keys with
|
57 | f09da76e | Kostas Papadimitriou | the provided value.
|
58 | f09da76e | Kostas Papadimitriou |
|
59 | f09da76e | Kostas Papadimitriou | >>> from django.conf import settings
|
60 | f09da76e | Kostas Papadimitriou | >>> from django.core import mail
|
61 | f09da76e | Kostas Papadimitriou | >>> with override_settings(settings, CONTACT_EMAILS=['kpap@grnet.gr'],
|
62 | f09da76e | Kostas Papadimitriou | >>> prefix='MYAPP_'):
|
63 | f09da76e | Kostas Papadimitriou | >>> from django.core.mail import send_mail
|
64 | f09da76e | Kostas Papadimitriou | >>> send_mail("hello", "I love you kpap", settings.DEFAULT_FROM_EMAIL,
|
65 | f09da76e | Kostas Papadimitriou | >>> settings.MYAPP_CONTACT_EMAILS)
|
66 | f09da76e | Kostas Papadimitriou | >>> assert 'kpap@grnet.gr' in mail.mailbox[0].recipients()
|
67 | f09da76e | Kostas Papadimitriou |
|
68 | f09da76e | Kostas Papadimitriou | If you plan to reuse it
|
69 | f09da76e | Kostas Papadimitriou |
|
70 | f09da76e | Kostas Papadimitriou | >>> import functools
|
71 | f09da76e | Kostas Papadimitriou | >>> from synnefo.util.testing import override_settings
|
72 | f09da76e | Kostas Papadimitriou | >>> from django.conf import settings
|
73 | f09da76e | Kostas Papadimitriou | >>> myapp_settings = functools.partial(override_settings, prefix='MYAPP_')
|
74 | f09da76e | Kostas Papadimitriou | >>> with myapp_settings(CONTACT_EMAILS=['kpap@grnet.gr'])
|
75 | f09da76e | Kostas Papadimitriou | >>> assert settings.MYAPP_CONTACT_EMAILS == ['kpap@grnet.gr']
|
76 | f09da76e | Kostas Papadimitriou |
|
77 | f09da76e | Kostas Papadimitriou | """
|
78 | f09da76e | Kostas Papadimitriou | |
79 | f09da76e | Kostas Papadimitriou | _prefix = kwargs.get('prefix', '') |
80 | f09da76e | Kostas Papadimitriou | prefix = lambda key: '%s%s' % (_prefix, key) |
81 | f09da76e | Kostas Papadimitriou | |
82 | f09da76e | Kostas Papadimitriou | oldkeys = [k for k in dir(settings) if k.upper() == k] |
83 | f09da76e | Kostas Papadimitriou | oldsettings = dict([(k, getattr(settings, k)) for k in oldkeys]) |
84 | f09da76e | Kostas Papadimitriou | |
85 | f09da76e | Kostas Papadimitriou | toremove = [] |
86 | f09da76e | Kostas Papadimitriou | for key, value in kwargs.iteritems(): |
87 | f09da76e | Kostas Papadimitriou | key = prefix(key) |
88 | f09da76e | Kostas Papadimitriou | if not hasattr(settings, key): |
89 | f09da76e | Kostas Papadimitriou | toremove.append(key) |
90 | f09da76e | Kostas Papadimitriou | setattr(settings, key, value)
|
91 | f09da76e | Kostas Papadimitriou | |
92 | f09da76e | Kostas Papadimitriou | yield
|
93 | f09da76e | Kostas Papadimitriou | |
94 | f09da76e | Kostas Papadimitriou | # Remove keys that didn't exist
|
95 | f09da76e | Kostas Papadimitriou | for key in toremove: |
96 | f09da76e | Kostas Papadimitriou | delattr(settings, key)
|
97 | f09da76e | Kostas Papadimitriou | |
98 | f09da76e | Kostas Papadimitriou | # Remove keys that added during the execution of the context
|
99 | f09da76e | Kostas Papadimitriou | if kwargs.get('reset_changes', True): |
100 | f09da76e | Kostas Papadimitriou | newkeys = [k for k in dir(settings) if k.upper() == k] |
101 | f09da76e | Kostas Papadimitriou | for key in newkeys: |
102 | f09da76e | Kostas Papadimitriou | if not key in oldkeys: |
103 | f09da76e | Kostas Papadimitriou | delattr(settings, key)
|
104 | f09da76e | Kostas Papadimitriou | |
105 | f09da76e | Kostas Papadimitriou | # Revert old keys
|
106 | f09da76e | Kostas Papadimitriou | for key in oldkeys: |
107 | f09da76e | Kostas Papadimitriou | if key == key.upper():
|
108 | f09da76e | Kostas Papadimitriou | setattr(settings, key, oldsettings.get(key))
|
109 | f09da76e | Kostas Papadimitriou | |
110 | f09da76e | Kostas Papadimitriou | |
111 | f09da76e | Kostas Papadimitriou | def with_settings(settings, prefix='', **override): |
112 | f09da76e | Kostas Papadimitriou | def wrapper(func): |
113 | f09da76e | Kostas Papadimitriou | def inner(*args, **kwargs): |
114 | f09da76e | Kostas Papadimitriou | with override_settings(settings, prefix=prefix, **override):
|
115 | f09da76e | Kostas Papadimitriou | ret = func(*args, **kwargs) |
116 | f09da76e | Kostas Papadimitriou | return ret
|
117 | f09da76e | Kostas Papadimitriou | return inner
|
118 | f09da76e | Kostas Papadimitriou | return wrapper
|
119 | d2b8ec7b | Christos Stavrakakis | |
120 | d2b8ec7b | Christos Stavrakakis | |
121 | d2b8ec7b | Christos Stavrakakis | @contextmanager
|
122 | d2b8ec7b | Christos Stavrakakis | def astakos_user(user): |
123 | d2b8ec7b | Christos Stavrakakis | """
|
124 | d2b8ec7b | Christos Stavrakakis | Context manager to mock astakos response.
|
125 | d2b8ec7b | Christos Stavrakakis |
|
126 | d2b8ec7b | Christos Stavrakakis | usage:
|
127 | d2b8ec7b | Christos Stavrakakis | with astakos_user("user@user.com"):
|
128 | d2b8ec7b | Christos Stavrakakis | .... make api calls ....
|
129 | d2b8ec7b | Christos Stavrakakis |
|
130 | d2b8ec7b | Christos Stavrakakis | """
|
131 | d2b8ec7b | Christos Stavrakakis | with patch("snf_django.lib.api.get_token") as get_token: |
132 | d2b8ec7b | Christos Stavrakakis | get_token.return_value = "DummyToken"
|
133 | d2b8ec7b | Christos Stavrakakis | with patch('astakosclient.AstakosClient.get_user_info') as m: |
134 | dcb8545f | Christos Stavrakakis | m.return_value = {"uuid": text.uenc(user, 'utf8')} |
135 | 3f9db536 | Christos Stavrakakis | with patch('astakosclient.AstakosClient.get_quotas') as m2: |
136 | 3f9db536 | Christos Stavrakakis | m2.return_value = { |
137 | 3f9db536 | Christos Stavrakakis | "system": {
|
138 | 3f9db536 | Christos Stavrakakis | "pithos.diskspace": {
|
139 | 3f9db536 | Christos Stavrakakis | "usage": 0, |
140 | 3f9db536 | Christos Stavrakakis | "limit": 1073741824, # 1GB |
141 | 3f9db536 | Christos Stavrakakis | "pending": 0 |
142 | 3f9db536 | Christos Stavrakakis | } |
143 | 3f9db536 | Christos Stavrakakis | } |
144 | 3f9db536 | Christos Stavrakakis | } |
145 | 3f9db536 | Christos Stavrakakis | issue_fun = "astakosclient.AstakosClient.issue_one_commission"
|
146 | 3f9db536 | Christos Stavrakakis | with patch(issue_fun) as m3: |
147 | 3f9db536 | Christos Stavrakakis | serials = [] |
148 | 3f9db536 | Christos Stavrakakis | append = serials.append |
149 | 3f9db536 | Christos Stavrakakis | |
150 | 3f9db536 | Christos Stavrakakis | def get_serial(*args, **kwargs): |
151 | 3f9db536 | Christos Stavrakakis | global serial
|
152 | 3f9db536 | Christos Stavrakakis | serial += 1
|
153 | 3f9db536 | Christos Stavrakakis | append(serial) |
154 | 3f9db536 | Christos Stavrakakis | return serial
|
155 | 3f9db536 | Christos Stavrakakis | |
156 | 3f9db536 | Christos Stavrakakis | m3.side_effect = get_serial |
157 | 3f9db536 | Christos Stavrakakis | resolv_fun = \ |
158 | 3f9db536 | Christos Stavrakakis | 'astakosclient.AstakosClient.resolve_commissions'
|
159 | 3f9db536 | Christos Stavrakakis | with patch(resolv_fun) as m4: |
160 | 3f9db536 | Christos Stavrakakis | m4.return_value = {'accepted': serials,
|
161 | 3f9db536 | Christos Stavrakakis | 'rejected': [],
|
162 | 3f9db536 | Christos Stavrakakis | 'failed': []}
|
163 | 3f9db536 | Christos Stavrakakis | users_fun = 'astakosclient.AstakosClient.get_usernames'
|
164 | 3f9db536 | Christos Stavrakakis | with patch(users_fun) as m5: |
165 | 3f9db536 | Christos Stavrakakis | |
166 | 3f9db536 | Christos Stavrakakis | def get_usernames(*args, **kwargs): |
167 | 3f9db536 | Christos Stavrakakis | uuids = args[-1]
|
168 | 3f9db536 | Christos Stavrakakis | return dict((uuid, uuid) for uuid in uuids) |
169 | 3f9db536 | Christos Stavrakakis | |
170 | 3f9db536 | Christos Stavrakakis | m5.side_effect = get_usernames |
171 | 3f9db536 | Christos Stavrakakis | yield
|
172 | 184a2a8c | Christos Stavrakakis | |
173 | 184a2a8c | Christos Stavrakakis | |
174 | 184a2a8c | Christos Stavrakakis | @contextmanager
|
175 | 184a2a8c | Christos Stavrakakis | def mocked_quotaholder(success=True): |
176 | 27899d6f | Christos Stavrakakis | with patch("synnefo.quotas.Quotaholder.get") as astakos: |
177 | 184a2a8c | Christos Stavrakakis | global serial
|
178 | f2080d16 | Christos Stavrakakis | serial += 10
|
179 | f2080d16 | Christos Stavrakakis | |
180 | f2080d16 | Christos Stavrakakis | def foo(*args, **kwargs): |
181 | f2080d16 | Christos Stavrakakis | return (len(astakos.return_value.issue_one_commission.mock_calls) + |
182 | f2080d16 | Christos Stavrakakis | serial) |
183 | f2080d16 | Christos Stavrakakis | astakos.return_value.issue_one_commission.side_effect = foo |
184 | 27899d6f | Christos Stavrakakis | astakos.return_value.resolve_commissions.return_value = {"failed": []}
|
185 | 184a2a8c | Christos Stavrakakis | yield
|
186 | 184a2a8c | Christos Stavrakakis | |
187 | d2b8ec7b | Christos Stavrakakis | |
188 | d2b8ec7b | Christos Stavrakakis | class BaseAPITest(TestCase): |
189 | d2b8ec7b | Christos Stavrakakis | def get(self, url, user='user', *args, **kwargs): |
190 | d2b8ec7b | Christos Stavrakakis | with astakos_user(user):
|
191 | d2b8ec7b | Christos Stavrakakis | response = self.client.get(url, *args, **kwargs)
|
192 | d2b8ec7b | Christos Stavrakakis | return response
|
193 | d2b8ec7b | Christos Stavrakakis | |
194 | d2b8ec7b | Christos Stavrakakis | def delete(self, url, user='user'): |
195 | d2b8ec7b | Christos Stavrakakis | with astakos_user(user):
|
196 | d2b8ec7b | Christos Stavrakakis | response = self.client.delete(url)
|
197 | d2b8ec7b | Christos Stavrakakis | return response
|
198 | d2b8ec7b | Christos Stavrakakis | |
199 | d2b8ec7b | Christos Stavrakakis | def post(self, url, user='user', params={}, ctype='json', *args, **kwargs): |
200 | d2b8ec7b | Christos Stavrakakis | if ctype == 'json': |
201 | d2b8ec7b | Christos Stavrakakis | content_type = 'application/json'
|
202 | d2b8ec7b | Christos Stavrakakis | with astakos_user(user):
|
203 | d2b8ec7b | Christos Stavrakakis | response = self.client.post(url, params, content_type=content_type,
|
204 | d2b8ec7b | Christos Stavrakakis | *args, **kwargs) |
205 | d2b8ec7b | Christos Stavrakakis | return response
|
206 | d2b8ec7b | Christos Stavrakakis | |
207 | d2b8ec7b | Christos Stavrakakis | def put(self, url, user='user', params={}, ctype='json', *args, **kwargs): |
208 | d2b8ec7b | Christos Stavrakakis | if ctype == 'json': |
209 | d2b8ec7b | Christos Stavrakakis | content_type = 'application/json'
|
210 | d2b8ec7b | Christos Stavrakakis | with astakos_user(user):
|
211 | d2b8ec7b | Christos Stavrakakis | response = self.client.put(url, params, content_type=content_type,
|
212 | d2b8ec7b | Christos Stavrakakis | *args, **kwargs) |
213 | d2b8ec7b | Christos Stavrakakis | return response
|
214 | d2b8ec7b | Christos Stavrakakis | |
215 | d2b8ec7b | Christos Stavrakakis | def assertSuccess(self, response): |
216 | d2b8ec7b | Christos Stavrakakis | self.assertTrue(response.status_code in [200, 203, 204]) |
217 | d2b8ec7b | Christos Stavrakakis | |
218 | d2b8ec7b | Christos Stavrakakis | def assertFault(self, response, status_code, name): |
219 | d2b8ec7b | Christos Stavrakakis | self.assertEqual(response.status_code, status_code)
|
220 | d2b8ec7b | Christos Stavrakakis | fault = json.loads(response.content) |
221 | d2b8ec7b | Christos Stavrakakis | self.assertEqual(fault.keys(), [name])
|
222 | d2b8ec7b | Christos Stavrakakis | |
223 | d2b8ec7b | Christos Stavrakakis | def assertBadRequest(self, response): |
224 | d2b8ec7b | Christos Stavrakakis | self.assertFault(response, 400, 'badRequest') |
225 | d2b8ec7b | Christos Stavrakakis | |
226 | d2b8ec7b | Christos Stavrakakis | def assertItemNotFound(self, response): |
227 | d2b8ec7b | Christos Stavrakakis | self.assertFault(response, 404, 'itemNotFound') |
228 | aba462a2 | Giorgos Korfiatis | |
229 | 2ad4eb80 | Kostas Papadimitriou | def assertMethodNotAllowed(self, response): |
230 | 2ad4eb80 | Kostas Papadimitriou | self.assertFault(response, 400, 'badRequest') |
231 | 2ad4eb80 | Kostas Papadimitriou | try:
|
232 | 2ad4eb80 | Kostas Papadimitriou | error = json.loads(response.content) |
233 | 2ad4eb80 | Kostas Papadimitriou | except ValueError: |
234 | 2ad4eb80 | Kostas Papadimitriou | self.assertTrue(False) |
235 | 2ad4eb80 | Kostas Papadimitriou | self.assertEqual(error['badRequest']['message'], 'Method not allowed') |
236 | 2ad4eb80 | Kostas Papadimitriou | |
237 | aba462a2 | Giorgos Korfiatis | |
238 | aba462a2 | Giorgos Korfiatis | # Imitate unittest assertions new in Python 2.7
|
239 | aba462a2 | Giorgos Korfiatis | |
240 | aba462a2 | Giorgos Korfiatis | class _AssertRaisesContext(object): |
241 | aba462a2 | Giorgos Korfiatis | """
|
242 | aba462a2 | Giorgos Korfiatis | A context manager used to implement TestCase.assertRaises* methods.
|
243 | aba462a2 | Giorgos Korfiatis | Adapted from unittest2.
|
244 | aba462a2 | Giorgos Korfiatis | """
|
245 | aba462a2 | Giorgos Korfiatis | |
246 | aba462a2 | Giorgos Korfiatis | def __init__(self, expected): |
247 | aba462a2 | Giorgos Korfiatis | self.expected = expected
|
248 | aba462a2 | Giorgos Korfiatis | |
249 | aba462a2 | Giorgos Korfiatis | def __enter__(self): |
250 | aba462a2 | Giorgos Korfiatis | return self |
251 | aba462a2 | Giorgos Korfiatis | |
252 | aba462a2 | Giorgos Korfiatis | def __exit__(self, exc_type, exc_value, tb): |
253 | aba462a2 | Giorgos Korfiatis | if exc_type is None: |
254 | aba462a2 | Giorgos Korfiatis | try:
|
255 | aba462a2 | Giorgos Korfiatis | exc_name = self.expected.__name__
|
256 | aba462a2 | Giorgos Korfiatis | except AttributeError: |
257 | aba462a2 | Giorgos Korfiatis | exc_name = str(self.expected) |
258 | aba462a2 | Giorgos Korfiatis | raise AssertionError( |
259 | aba462a2 | Giorgos Korfiatis | "%s not raised" % (exc_name,))
|
260 | aba462a2 | Giorgos Korfiatis | if not issubclass(exc_type, self.expected): |
261 | aba462a2 | Giorgos Korfiatis | # let unexpected exceptions pass through
|
262 | aba462a2 | Giorgos Korfiatis | return False |
263 | aba462a2 | Giorgos Korfiatis | self.exception = exc_value # store for later retrieval |
264 | aba462a2 | Giorgos Korfiatis | return True |
265 | aba462a2 | Giorgos Korfiatis | |
266 | aba462a2 | Giorgos Korfiatis | |
267 | aba462a2 | Giorgos Korfiatis | def assertRaises(excClass): |
268 | aba462a2 | Giorgos Korfiatis | return _AssertRaisesContext(excClass)
|
269 | aba462a2 | Giorgos Korfiatis | |
270 | aba462a2 | Giorgos Korfiatis | |
271 | aba462a2 | Giorgos Korfiatis | def assertGreater(x, y): |
272 | aba462a2 | Giorgos Korfiatis | assert x > y
|
273 | aba462a2 | Giorgos Korfiatis | |
274 | aba462a2 | Giorgos Korfiatis | |
275 | aba462a2 | Giorgos Korfiatis | def assertIn(x, y): |
276 | aba462a2 | Giorgos Korfiatis | assert x in y |