Statistics
| Branch: | Tag: | Revision:

root / logic / tests.py @ af90d919

History | View | Annotate | Download (13.5 kB)

1
# vim: set fileencoding=utf-8 :
2
# Copyright 2011 GRNET S.A. All rights reserved.
3
#
4
# Redistribution and use in source and binary forms, with or without
5
# modification, are permitted provided that the following conditions
6
# are met:
7
#
8
#   1. Redistributions of source code must retain the above copyright
9
#      notice, this list of conditions and the following disclaimer.
10
#
11
#  2. Redistributions in binary form must reproduce the above copyright
12
#     notice, this list of conditions and the following disclaimer in the
13
#     documentation and/or other materials provided with the distribution.
14
#
15
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
# SUCH DAMAGE.
26
#
27
# The views and conclusions contained in the software and documentation are
28
# those of the authors and should not be interpreted as representing official
29
# policies, either expressed or implied, of GRNET S.A.
30

    
31
# Provides automated tests for logic module
32

    
33
import time
34
import hashlib
35
from random import randint
36

    
37
from django.test import TestCase
38
from django.conf import settings
39

    
40
from synnefo.db.models import *
41
from synnefo.logic import backend
42
from synnefo.logic import credits
43
from synnefo.logic import users
44
from synnefo.logic.utils import get_rsapi_state
45

    
46

    
47
class CostsTestCase(TestCase):
48
    fixtures = ['db_test_data']
49

    
50
    def test_get_costs(self):
51
        """Test the Flavor cost-related methods method"""
52
        # first an easy test, a Flavor with only one FlavorCost entry
53
        flavor = Flavor.objects.get(pk=30001)
54

    
55
        start_date = datetime.datetime(year=2010, month=1, day=1)
56
        end_date = datetime.datetime(year=2010, month=1, day=2)
57

    
58
        # we now that the cost should be 5*24 (inactive) and 10*24 (active)
59
        r_active = credits.get_cost_active(flavor, start_date, end_date)
60
        r_inactive = credits.get_cost_inactive(flavor, start_date, end_date)
61

    
62
        self.assertEqual(len(r_active), 1, 'get_cost_active() should have returned 1 entry (%d)' %(len(r_active),))
63
        self.assertEqual(len(r_inactive), 1, 'get_cost_inactive() should have returned 1 entry (%d)'% (len(r_inactive),))
64

    
65
        self.assertEqual(10*24, r_active[0][1], 'get_cost_active() is not working properly (%d!=%d)' % (r_active[0][1], 10*24))
66
        self.assertEqual(5*24, r_inactive[0][1], 'get_cost_inactive() is not working properly (%d!=%d)' % (r_inactive[0][1], 5*24))
67

    
68
        # The second test, will involve a more complex cost example
69
        # The overall cost will be calculated by two FlavorCost entries
70

    
71
        flavor = Flavor.objects.get(pk=30000)
72

    
73
        start_date = datetime.datetime(year=2010, month=12, day=31)
74
        end_date = datetime.datetime(year=2011, month=01, day=2)
75

    
76
        # this is more complicated, active costs are 5*24 + 10*24 = 360
77
        # and inactive costs are 2*24 + 5*24 = 168
78

    
79
        r_active = credits.get_cost_active(flavor, start_date, end_date)
80
        r_inactive = credits.get_cost_inactive(flavor, start_date, end_date)
81

    
82
        self.assertEqual(len(r_active), 2, 'get_cost_active() should have returned 2 entries (%d)' %(len(r_active),))
83
        self.assertEqual(len(r_inactive), 2, 'get_cost_inactive() should have returned 2 entries (%d)'% (len(r_inactive),))
84

    
85
        ta_cost = sum([x[1] for x in r_active])
86
        tia_cost = sum([x[1] for x in r_inactive])
87

    
88
        self.assertEqual(360, ta_cost, 'get_cost_active() is not working properly (%d!=%d)' % (ta_cost, 360))
89
        self.assertEqual(168, tia_cost, 'get_cost_inactive() is not working properly (%d!=%d)' % (tia_cost, 168))
90

    
91
        
92
class ChargeTestCase(TestCase):
93
    fixtures = ['db_test_data']
94

    
95
    def test_charge_method(self):
96
        """Test VirtualMachine.charge() method"""
97

    
98
        # Since we have tested the costs, with this test
99
        # we must ensure the following:
100
        # 1. The vm.charged is updated
101
        # 2. Users credits are decreased
102

    
103
        vm_started = VirtualMachine.objects.get(pk=30000)
104

    
105
        initial_date = vm_started.charged
106
        initial_credits = vm_started.owner.credit
107

    
108
        credits.charge(vm_started)
109

    
110
        self.assertTrue(vm_started.charged > initial_date, 'Initial charged date should not be greater')
111
        self.assertTrue(initial_credits > vm_started.owner.credit, 'The user should have less credits now! (%d>%d)' % (initial_credits, vm_started.owner.credit))
112

    
113

    
114
class DebitAccountTestCase(TestCase):
115
    fixtures = ['db_test_data']
116

    
117
    def test_debit_account(self):
118
        """Test a SynnefoUser object"""
119
        s_user = SynnefoUser.objects.get(pk=30000)
120
        v_machine = VirtualMachine.objects.get(pk=30000)
121

    
122
        # charge the user
123
        credits.debit_account(s_user, 10, v_machine, "This should be a structured debit message!")
124

    
125
        # should have only one debit object
126
        d_list = Debit.objects.all()
127

    
128
        self.assertEqual(len(d_list), 1, 'debit_account() writes more than one or zero (%d) debit entries!' % ( len(d_list), ))
129

    
130
        # retrieve the user, now he/she should have zero credits
131
        s_user = SynnefoUser.objects.get(pk=30000)
132

    
133
        self.assertEqual(0, s_user.credit, 'SynnefoUser (pk=30000) should have zero credits (%d)' % ( s_user.credit, ))
134

    
135

    
136
class AuthTestCase(TestCase):
137
    fixtures = ['db_test_data']
138

    
139
    def _register_user(self):
140
        users.register_student ("Jimmy Page", "jpage", "jpage@zoso.com")
141
        self.user = SynnefoUser.objects.get(name = "jpage")
142

    
143
    def test_register(self):
144
        """ test user registration
145
        """
146
        self._register_user()
147
        self.assertNotEquals(self.user, None)
148

    
149
        #Check hash generation
150
        md5 = hashlib.md5()
151
        md5.update(self.user.uniq)
152
        md5.update(self.user.name)
153
        md5.update(time.asctime())
154

    
155
        self.assertEquals(self.user.auth_token, md5.hexdigest())
156

    
157
    def test_del_user(self):
158
        """ test user deletion
159
        """
160
        self._register_user()
161
        self.assertNotEquals(self.user, None)
162
        
163
        users.delete_user(self.user)
164

    
165
        self.assertRaises(SynnefoUser.DoesNotExist, SynnefoUser.objects.get,
166
                          name = "jpage")
167

    
168

    
169
class ProcessOpStatusTestCase(TestCase):
170
    fixtures = ['db_test_data']
171
    msg_op = {
172
        'instance': 'instance-name',
173
        'type': 'ganeti-op-status',
174
        'operation': 'OP_INSTANCE_STARTUP',
175
        'jobId': 0,
176
        'status': 'success',
177
        'logmsg': 'unittest - simulated message'
178
    }
179

    
180
    def test_op_startup_success(self):
181
        """Test notification for successful OP_INSTANCE_START"""
182
        msg = self.msg_op
183
        msg['operation'] = 'OP_INSTANCE_STARTUP'
184
        msg['status'] = 'success'
185

    
186
        # This machine is initially in BUILD
187
        vm = VirtualMachine.objects.get(pk=30002)
188
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
189
                                  msg["status"], msg["logmsg"])
190
        self.assertEquals(get_rsapi_state(vm), 'ACTIVE')
191

    
192
    def test_op_shutdown_success(self):
193
        """Test notification for successful OP_INSTANCE_SHUTDOWN"""
194
        msg = self.msg_op
195
        msg['operation'] = 'OP_INSTANCE_SHUTDOWN'
196
        msg['status'] = 'success'
197

    
198
        # This machine is initially in BUILD
199
        vm = VirtualMachine.objects.get(pk=30002)
200
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
201
                                  msg["status"], msg["logmsg"])
202
        self.assertEquals(get_rsapi_state(vm), 'STOPPED')
203

    
204
    def test_op_reboot_success(self):
205
        """Test notification for successful OP_INSTANCE_REBOOT"""
206
        msg = self.msg_op
207
        msg['operation'] = 'OP_INSTANCE_REBOOT'
208
        msg['status'] = 'success'
209

    
210
        # This machine is initially in BUILD
211
        vm = VirtualMachine.objects.get(pk=30002)
212
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
213
                                  msg["status"], msg["logmsg"])
214
        self.assertEquals(get_rsapi_state(vm), 'ACTIVE')
215

    
216
    def test_op_create_success(self):
217
        """Test notification for successful OP_INSTANCE_CREATE"""
218
        msg = self.msg_op
219
        msg['operation'] = 'OP_INSTANCE_CREATE'
220
        msg['status'] = 'success'
221

    
222
        # This machine is initially in BUILD
223
        vm = VirtualMachine.objects.get(pk=30002)
224
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
225
                                  msg["status"], msg["logmsg"])
226
        self.assertEquals(get_rsapi_state(vm), 'ACTIVE')
227

    
228
    def test_op_remove_success(self):
229
        """Test notification for successful OP_INSTANCE_REMOVE"""
230
        msg = self.msg_op
231
        msg['operation'] = 'OP_INSTANCE_REMOVE'
232
        msg['status'] = 'success'
233

    
234
        # This machine is initially in BUILD
235
        vm = VirtualMachine.objects.get(pk=30002)
236
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
237
                                  msg["status"], msg["logmsg"])
238
        self.assertEquals(get_rsapi_state(vm), 'DELETED')
239
        self.assertTrue(vm.deleted)
240

    
241
    def test_unknown_op(self):
242
        """Test notification for unknown Ganeti op raises exception"""
243
        msg = self.msg_op
244
        msg['operation'] = 'OP_INSTANCE_SOMETHING_ELSE'
245
        msg['status'] = 'success'
246

    
247
        # This machine is initially in BUILD
248
        vm = VirtualMachine.objects.get(pk=30002)
249
        self.assertRaises(VirtualMachine.InvalidBackendMsgError,
250
                          backend.process_op_status,
251
                          vm, msg["jobId"], msg["operation"],
252
                          msg["status"], msg["logmsg"])
253

    
254
    def test_op_create_error(self):
255
        """Test notification for failed OP_INSTANCE_CREATE"""
256
        msg = self.msg_op
257
        msg['operation'] = 'OP_INSTANCE_CREATE'
258
        msg['status'] = 'error'
259

    
260
        # This machine is initially in BUILD
261
        vm = VirtualMachine.objects.get(pk=30002)
262
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
263
                                  msg["status"], msg["logmsg"])
264
        self.assertEquals(get_rsapi_state(vm), 'ERROR')
265
        self.assertFalse(vm.deleted)
266

    
267
    def test_remove_machine_in_error(self):
268
        """Test notification for failed OP_INSTANCE_REMOVE, server in ERROR"""
269
        msg = self.msg_op
270
        msg['operation'] = 'OP_INSTANCE_REMOVE'
271
        msg['status'] = 'error'
272

    
273
        # This machine is initially in BUILD
274
        vm = VirtualMachine.objects.get(pk=30002)
275
        backend.process_op_status(vm, 0, "OP_INSTANCE_CREATE", "error", "test")
276
        self.assertEquals(get_rsapi_state(vm), 'ERROR')
277

    
278
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
279
                                  msg["status"], msg["logmsg"])
280
        self.assertEquals(get_rsapi_state(vm), 'DELETED')
281
        self.assertTrue(vm.deleted)
282

    
283

    
284
class ProcessNetStatusTestCase(TestCase):
285
    fixtures = ['db_test_data']
286

    
287
    def test_set_ipv4(self):
288
        """Test reception of a net status notification"""
289
        msg = {'instance': 'instance-name',
290
               'type':     'ganeti-net-status',
291
               'nics': [
292
                   {'ip': '192.168.33.1', 'mac': 'aa:00:00:58:1e:b9'}
293
               ]
294
        }
295
        vm = VirtualMachine.objects.get(pk=30000)
296
        backend.process_net_status(vm, msg['nics'])
297
        self.assertEquals(vm.nics.all()[0].ipv4, '192.168.33.1')
298

    
299
    def test_set_empty_ipv4(self):
300
        """Test reception of a net status notification with no IPv4 assigned"""
301
        msg = {'instance': 'instance-name',
302
               'type':     'ganeti-net-status',
303
               'nics': [
304
                   {'ip': '', 'mac': 'aa:00:00:58:1e:b9'}
305
               ]
306
        }
307
        vm = VirtualMachine.objects.get(pk=30000)
308
        backend.process_net_status(vm, msg['nics'])
309
        self.assertEquals(vm.nics.all()[0].ipv4, '')
310

    
311

    
312
class UsersTestCase(TestCase):
313
    def test_create_uname(self):
314
        username = users.create_uname("Donald Knuth")
315
        self.assertEquals(username, "knuthd")
316

    
317
        username = users.create_uname("Nemichandra Siddhanta Chakravati")
318
        self.assertEquals(username, "chakravn")
319

    
320
        username = users.create_uname(u'Γεώργιος Παπαγεωργίου')
321
        self.assertEquals(username, u'παπαγεωγ')
322

    
323

    
324
class ProcessProgressUpdateTestCase(TestCase):
325
    fixtures = ['db_test_data']
326

    
327
    def test_progress_update(self):
328
        """Test reception of a create progress notification"""
329

    
330
        # This machine is in BUILD
331
        vm = VirtualMachine.objects.get(pk=30002)
332
        rprogress = randint(10, 100)
333

    
334
        backend.process_create_progress(vm, rprogress, 0)
335
        self.assertEquals(vm.buildpercentage, rprogress)
336

    
337
        self.assertRaises(ValueError, backend.process_create_progress,
338
                          vm, 9, 0)
339
        self.assertRaises(ValueError, backend.process_create_progress,
340
                          vm, -1, 0)
341
        self.assertRaises(ValueError, backend.process_create_progress,
342
                          vm, 'a', 0)
343

    
344
        # This machine is ACTIVE
345
        #vm = VirtualMachine.objects.get(pk=30000)
346
        #self.assertRaises(VirtualMachine.IllegalState,
347
        #                  backend.process_create_progress, vm, 1)
348