Ticket #6231 - Overview: resources used does not show when user has a quota but no...
[ganeti_webmgr.git] / ganeti_web / tests / ganeti_errors.py
blobd928d4d36dbdbdfea77596f14ad900d0cd86f835
1 # Copyright (C) 2010 Oregon State University et al.
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
16 # USA.
18 from datetime import datetime
20 from django.test import TestCase
21 from django.test.client import Client
23 from util import client
24 from ganeti_web.tests.call_proxy import CallProxy
25 from ganeti_web.tests.rapi_proxy import RapiProxy
26 from django.contrib.auth.models import User
27 from ganeti_web import models
29 VirtualMachine = models.VirtualMachine
30 Cluster = models.Cluster
31 GanetiError = models.GanetiError
32 GanetiErrorManager = models.GanetiErrorManager
34 __all__ = ('TestGanetiErrorModel','TestErrorViews')
36 class TestGanetiErrorBase():
37 """
38 Class for testing ganeti error storage.
39 """
41 def setUp(self):
42 self.tearDown()
43 models.client.GanetiRapiClient = RapiProxy
45 def tearDown(self):
46 VirtualMachine.objects.all().delete()
47 Cluster.objects.all().delete()
48 GanetiError.objects.all().delete()
49 RapiProxy.error = None
51 def create_model(self, class_, *args, **kwargs):
52 """
53 create an instance of the model being tested, this will instrument
54 some methods of the model to check if they have been called
55 """
56 obj = class_.objects.create(*args, **kwargs)
58 # patch model class
59 CallProxy.patch(obj, 'parse_transient_info')
60 CallProxy.patch(obj, 'parse_persistent_info')
61 CallProxy.patch(obj, '_refresh')
62 CallProxy.patch(obj, 'load_info')
63 CallProxy.patch(obj, 'save')
64 return obj
67 class TestGanetiErrorModel(TestGanetiErrorBase, TestCase):
68 """
69 Class for testing ganeti error storage.
70 """
72 # TODO: add tests for clusters/vms in get_errors
73 # TODO: maybe split into individual tests? Not sure
74 def test_manager_methods(self):
75 """
76 Test useful GanetiErrorManager methods:
77 * store_error
78 * get_errors
79 * clear_errors
80 * clear_error
81 * remove_errors
83 Verifies:
84 * all those methods are free of errors
85 """
86 cluster0 = self.create_model(Cluster, hostname="test0", slug="OSL_TEST0")
87 cluster1 = self.create_model(Cluster, hostname="test1", slug="OSL_TEST1")
88 cluster2 = self.create_model(Cluster, hostname="test2", slug="OSL_TEST2")
89 vm0 = self.create_model(VirtualMachine,cluster=cluster0, hostname="vm0.test.org")
90 vm1 = self.create_model(VirtualMachine,cluster=cluster1, hostname="vm1.test.org")
92 msg = client.GanetiApiError("Simulating an error", 777)
93 RapiProxy.error = msg
95 # test store_error
96 store_error = GanetiError.objects.store_error
97 store_error(str(msg), obj=cluster0, code=msg.code)
98 store_error(str(msg), obj=cluster1, code=msg.code)
99 store_error(str(msg), obj=cluster2, code=msg.code)
100 store_error(str(msg), obj=vm0, code=msg.code)
101 store_error(str(msg), obj=vm1, code=msg.code)
103 # test get_errors
104 get_errors = GanetiError.objects.get_errors
106 errors = get_errors(msg=str(msg))
107 self.assertEqual(len(errors), 5)
108 errors = get_errors(msg=str(msg) + "NOTHING")
109 self.assertEqual(len(errors), 0)
111 errors = get_errors(code=msg.code)
112 self.assertEqual(len(errors), 5)
113 errors = get_errors(code=msg.code + 123)
114 self.assertEqual(len(errors), 0)
116 errors = get_errors(obj=cluster0)
117 self.assertEqual(len(errors), 2)
118 errors = get_errors(obj=cluster1)
119 self.assertEqual(len(errors), 2)
120 errors = get_errors(obj=cluster2)
121 self.assertEqual(len(errors), 1)
123 errors = get_errors(obj=vm0)
124 self.assertEqual(len(errors), 1)
125 errors = get_errors(obj=vm1)
126 self.assertEqual(len(errors), 1)
128 errors = get_errors(obj=Cluster.objects.all())
129 self.assertEqual(len(errors), 5)
130 errors = get_errors(obj=VirtualMachine.objects.all())
131 self.assertEqual(len(errors), 2)
133 # test clear_error(s)
134 clear_error = GanetiError.objects.clear_error
135 clear_errors = GanetiError.objects.clear_errors
137 errors = get_errors()
138 self.assertEqual(len(errors), 5)
139 errors = get_errors(cleared=False).order_by("id")
140 self.assertEqual(len(errors), 5)
142 clear_error(errors[0].id)
143 errors = get_errors()
144 self.assertEqual(len(errors), 5)
145 errors = get_errors(cleared=False)
146 self.assertEqual(len(errors), 4)
148 clear_errors(obj=cluster2)
149 errors = get_errors()
150 self.assertEqual(len(errors), 5)
151 errors = get_errors(cleared=False)
152 self.assertEqual(len(errors), 3)
154 clear_errors(obj=vm1)
155 errors = get_errors()
156 self.assertEqual(len(errors), 5)
157 errors = get_errors(cleared=False)
158 self.assertEqual(len(errors), 2)
160 clear_errors(msg=str(msg))
161 errors = get_errors()
162 self.assertEqual(len(errors), 5)
163 errors = get_errors(cleared=False)
164 self.assertEqual(len(errors), 0)
166 # test remove_errors
167 remove_errors = GanetiError.objects.remove_errors
169 errors = get_errors()
170 self.assertEqual(len(errors), 5)
172 remove_errors(obj=cluster2)
173 errors = get_errors()
174 self.assertEqual(len(errors), 4)
176 remove_errors(obj=vm1)
177 errors = get_errors()
178 self.assertEqual(len(errors), 3)
180 remove_errors(msg=str(msg))
181 errors = get_errors()
182 self.assertEqual(len(errors), 0)
184 def test_specified_code_values(self):
186 Test if errors with code in (401, 404) are stored in a proper way.
187 See tickets #2877, #2883.
189 Verifies:
190 * Manager store_error works properly for specific code numbers
192 cluster0 = self.create_model(Cluster, hostname="test0", slug="OSL_TEST0")
193 vm0 = self.create_model(VirtualMachine,cluster=cluster0, hostname="vm0.test.org")
195 msg0 = client.GanetiApiError("Simulating 401 error", 401)
196 msg1 = client.GanetiApiError("Simulating 404 error", 404)
197 RapiProxy.error = msg0
199 store_error = GanetiError.objects.store_error
200 get_errors = GanetiError.objects.get_errors
201 remove_errors = GanetiError.objects.remove_errors
203 # 401 - cluster
204 store_error(str(msg0), obj=cluster0, code=msg0.code)
205 errors = get_errors(obj=cluster0)
206 self.assertEqual(len(errors), 1)
207 errors = get_errors(obj=vm0)
208 self.assertEqual(len(errors), 0)
209 remove_errors(obj=cluster0)
211 # 401 - VM
212 store_error(str(msg0), obj=vm0, code=msg0.code)
213 errors = get_errors(obj=cluster0)
214 self.assertEqual(len(errors), 1)
215 errors = get_errors(obj=vm0)
216 self.assertEqual(len(errors), 0)
217 remove_errors(obj=cluster0)
218 remove_errors(obj=vm0)
220 # 404 - VM
221 store_error(str(msg1), obj=vm0, code=msg1.code)
222 errors = get_errors(obj=cluster0)
223 self.assertEqual(len(errors), 1)
224 errors = get_errors(obj=vm0)
225 self.assertEqual(len(errors), 1)
226 remove_errors(obj=cluster0)
227 remove_errors(obj=vm0)
229 # 404 - cluster
230 store_error(str(msg1), obj=cluster0, code=msg1.code)
231 errors = get_errors(obj=cluster0)
232 self.assertEqual(len(errors), 1)
233 errors = get_errors(obj=vm0)
234 self.assertEqual(len(errors), 0)
236 # 404 - VM, but error is really with cluster
237 store_error(str(msg1), obj=vm0, code=msg1.code)
238 errors = get_errors(obj=cluster0)
239 self.assertEqual(len(errors), 1)
240 errors = get_errors(obj=vm0)
241 self.assertEqual(len(errors), 0)
242 remove_errors(obj=cluster0)
244 def refresh(self, object):
246 NOTE: this test is borrowed from TestCachedClusterObject.
248 Test forced refresh of cached data
250 Verifies:
251 * Object specific refresh is called
252 * Info is parsed
253 * Object is saved
254 * Cache time is updated
256 now = datetime.now()
257 object.refresh()
259 object._refresh.assertCalled(self)
260 object.parse_transient_info.assertCalled(self)
261 object.parse_persistent_info.assertCalled(self)
262 self.assertEqual(1, len(object.parse_persistent_info.calls))
263 self.assert_(object.id)
264 self.assertNotEqual(None, object.cached)
265 self.assert_(now < object.cached, "Cache time should be newer")
267 def test_refresh_error(self):
269 Test an error during refresh
271 Verifies:
272 * error will be saved as GanetiError object
273 * successful refresh after will clear error
275 cluster0 = self.create_model(Cluster, hostname="test0", slug="OSL_TEST0")
276 cluster1 = self.create_model(Cluster, hostname="test1", slug="OSL_TEST1")
277 vm0 = self.create_model(VirtualMachine,cluster=cluster0, hostname="vm0.test.org")
278 vm1 = self.create_model(VirtualMachine,cluster=cluster1, hostname="vm1.test.org")
280 msg = client.GanetiApiError("Simulating an error", 777)
281 RapiProxy.error = msg
283 # force an error on all objects to test its capture
284 for i in (cluster0, cluster1, vm0, vm1):
285 i.refresh()
286 self.assertEqual(str(msg), i.error)
288 # get errors for object
289 # TODO: check log format
290 if isinstance(i, VirtualMachine):
291 errors = GanetiError.objects.get_errors(obj=i.cluster)
292 self.assertEqual(2, len(errors))
293 self.assertEqual(errors[0].cleared, False)
294 self.assertEqual(errors[1].cleared, False)
295 self.assertEqual(errors[0].msg, str(msg))
296 self.assertEqual(errors[1].msg, str(msg))
297 self.assertEqual(errors[0].code, msg.code)
298 self.assertEqual(errors[1].code, msg.code)
300 cleared = GanetiError.objects.get_errors(obj=i.cluster, cleared=True)
301 self.assertEqual(0, len(cleared))
303 else:
304 errors = GanetiError.objects.get_errors(obj=i)
305 self.assertEqual(1, len(errors))
306 self.assertEqual(errors[0].cleared, False)
307 self.assertEqual(errors[0].msg, str(msg))
308 self.assertEqual(errors[0].code, msg.code)
310 cleared = GanetiError.objects.get_errors(obj=i, cleared=True)
311 self.assertEqual(0, len(cleared))
313 # set all errors as cleared and test if it was a success
314 for i in (cluster0, cluster1, vm0, vm1):
315 if isinstance(i, VirtualMachine):
316 GanetiError.objects.clear_errors(obj=i.cluster)
318 cleared = GanetiError.objects.get_errors(obj=i.cluster, cleared=True)
319 self.assertEqual(2, len(cleared))
320 self.assertEqual(cleared[0].cleared, True)
321 self.assertEqual(cleared[1].cleared, True)
322 self.assertEqual(cleared[0].msg, str(msg))
323 self.assertEqual(cleared[1].msg, str(msg))
324 self.assertEqual(cleared[0].code, msg.code)
325 self.assertEqual(cleared[1].code, msg.code)
327 else:
328 GanetiError.objects.clear_errors(obj=i)
330 cleared = GanetiError.objects.get_errors(obj=i, cleared=True)
331 self.assertEqual(2, len(cleared))
332 self.assertEqual(cleared[0].cleared, True)
333 self.assertEqual(cleared[1].cleared, True)
334 self.assertEqual(cleared[0].msg, str(msg))
335 self.assertEqual(cleared[1].msg, str(msg))
336 self.assertEqual(cleared[0].code, msg.code)
337 self.assertEqual(cleared[1].code, msg.code)
339 # clear the error and retry
340 RapiProxy.error = None
342 for i in (cluster0, cluster1, vm0, vm1):
343 self.refresh(i)
344 self.assertEqual(None, i.error)
347 class TestErrorViews(TestGanetiErrorBase, TestCase):
349 def setUp(self):
350 super(TestErrorViews, self).setUp()
352 user = User(id=2, username='tester0')
353 user.set_password('secret')
354 user.save()
356 d = globals()
357 d['user'] = user
358 d['cluster'] = self.create_model(Cluster, hostname="test0", slug="OSL_TEST0")
359 d['vm'] = self.create_model(VirtualMachine,cluster=cluster, hostname="vm0.test.org")
360 d['c'] = Client()
362 def tearDown(self):
363 super(TestErrorViews, self).tearDown()
364 User.objects.all().delete()
366 def test_clear_error(self):
368 url = '/error/clear/%s'
371 msg = client.GanetiApiError("Simulating an error", 777)
372 RapiProxy.error = msg
374 # test store_error
375 store_error = GanetiError.objects.store_error
376 c_error = store_error(str(msg), obj=cluster, code=msg.code)
377 c_error = GanetiError.objects.get(pk=c_error.pk)
378 self.assertFalse(c_error.cleared)
380 vm_error = store_error(str(msg), obj=vm, code=msg.code)
381 vm_error = GanetiError.objects.get(pk=vm_error.pk)
382 self.assertFalse(vm_error.cleared)
384 # anonymous user
385 response = c.post(url % vm_error.id, follow=True)
386 self.assertEqual(200, response.status_code)
387 self.assertTemplateUsed(response, 'registration/login.html')
388 vm_error = GanetiError.objects.get(pk=vm_error.pk)
389 self.assertFalse(vm_error.cleared)
391 # unauthorized user
392 self.assert_(c.login(username=user.username, password='secret'))
393 response = c.post(url % vm_error.id)
394 self.assertEqual(403, response.status_code)
395 vm_error = GanetiError.objects.get(pk=vm_error.pk)
396 self.assertFalse(vm_error.cleared)
398 # nonexisent error
399 response = c.post(url % -1)
400 self.assertEqual(404, response.status_code)
402 # authorized for cluster (cluster admin)
403 user.grant('admin', cluster)
404 response = c.post(url % c_error.id)
405 self.assertEqual(200, response.status_code)
406 c_error = GanetiError.objects.get(pk=c_error.pk)
407 self.assert_(c_error.cleared)
408 GanetiError.objects.all().update(cleared=False)
410 # authorized for vm (cluster admin)
411 response = c.post(url % vm_error.id)
412 self.assertEqual(200, response.status_code)
413 vm_error = GanetiError.objects.get(pk=vm_error.pk)
414 self.assert_(vm_error.cleared)
415 GanetiError.objects.all().update(cleared=False)
416 user.revoke_all(cluster)
418 # authorized for vm (vm owner)
419 vm.owner = user.get_profile()
420 vm.save()
421 response = c.post(url % vm_error.id)
422 self.assertEqual(200, response.status_code)
423 vm_error = GanetiError.objects.get(pk=vm_error.pk)
424 self.assert_(vm_error.cleared)
425 GanetiError.objects.all().update(cleared=False)
426 vm.owner = None
427 vm.save()
429 # authorized for vm (superuser)
430 user.is_superuser = True
431 user.save()
432 response = c.post(url % vm_error.id)
433 self.assertEqual(200, response.status_code)
434 vm_error = GanetiError.objects.get(pk=vm_error.pk)
435 self.assert_(vm_error.cleared)
436 GanetiError.objects.all().update(cleared=False)