Revision c8908e51
b/snf-cyclades-app/synnefo/db/tests.py | ||
---|---|---|
1 |
# Copyright 2011 GRNET S.A. All rights reserved.
|
|
1 |
# Copyright 2012 GRNET S.A. All rights reserved.
|
|
2 | 2 |
# |
3 | 3 |
# Redistribution and use in source and binary forms, with or without |
4 | 4 |
# modification, are permitted provided that the following conditions |
... | ... | |
31 | 31 |
# |
32 | 32 |
# Provides automated tests for db module |
33 | 33 |
|
34 |
from synnefo.db.models import * |
|
35 | 34 |
from django.test import TestCase |
36 | 35 |
|
37 | 36 |
# Import pool tests |
38 | 37 |
from synnefo.db.pools.tests import * |
39 | 38 |
|
39 |
from synnefo.db.models import * |
|
40 |
from synnefo.db import models_factory as mfact |
|
41 |
from synnefo.db.pools import IPPool |
|
42 |
|
|
43 |
from django.db import IntegrityError |
|
44 |
from django.core.exceptions import MultipleObjectsReturned |
|
45 |
from mock import patch |
|
46 |
|
|
47 |
|
|
48 |
class FlavorTest(TestCase): |
|
49 |
def test_flavor_name(self): |
|
50 |
"""Test a flavor object name method.""" |
|
51 |
flavor = mfact.FlavorFactory(cpu=1, ram=1024, disk=40) |
|
52 |
self.assertEqual(flavor.name, "C1R1024D40", "flavor.name is not" |
|
53 |
" generated correctly. Name is %s instead of C1R1055D40" % |
|
54 |
flavor.name) |
|
55 |
|
|
56 |
|
|
57 |
class BackendTest(TestCase): |
|
58 |
def setUp(self): |
|
59 |
self.backend = mfact.BackendFactory() |
|
60 |
|
|
61 |
@patch("synnefo.db.models.get_rapi_client") |
|
62 |
def test_get_client(self, client): |
|
63 |
id_ = self.backend.id |
|
64 |
hash_ = self.backend.hash |
|
65 |
name = self.backend.clustername |
|
66 |
passwd = self.backend.password |
|
67 |
user = self.backend.username |
|
68 |
port = self.backend.port |
|
69 |
self.backend.get_client() |
|
70 |
client.assert_called_once_with(id_, hash_, name, port, user, passwd) |
|
71 |
|
|
72 |
def test_save_hash(self): |
|
73 |
"""Test that backend hash is generated on credential change""" |
|
74 |
old_hash = self.backend.hash |
|
75 |
for field in ['clustername', 'username', 'password', 'port']: |
|
76 |
value = 5181 if field == 'port' else 'foo' |
|
77 |
self.backend.__setattr__(field, value) |
|
78 |
self.backend.save() |
|
79 |
self.assertNotEqual(old_hash, self.backend.hash) |
|
80 |
old_hash = self.backend.hash |
|
81 |
|
|
82 |
def test_unique_index(self): |
|
83 |
"""Test that each backend gets a unique index""" |
|
84 |
backends = [self.backend] |
|
85 |
for i in xrange(0, 14): |
|
86 |
backends.append(mfact.BackendFactory()) |
|
87 |
indexes = map(lambda x: x.index, backends) |
|
88 |
self.assertEqual(len(indexes), len(set(indexes))) |
|
89 |
|
|
90 |
def test_backend_number(self): |
|
91 |
"""Test that no more than 16 backends are created""" |
|
92 |
for i in xrange(0, 14): |
|
93 |
mfact.BackendFactory() |
|
94 |
self.assertRaises(Exception, mfact.BackendFactory, ()) |
|
95 |
|
|
96 |
def test_delete_backend(self): |
|
97 |
vm = mfact.VirtualMachineFactory(backend=self.backend, deleted=True) |
|
98 |
bnet = mfact.BackendNetworkFactory(backend=self.backend) |
|
99 |
self.backend.delete() |
|
100 |
self.assertRaises(Backend.DoesNotExist, Backend.objects.get, |
|
101 |
id=self.backend.id) |
|
102 |
# Test that VM is not deleted |
|
103 |
vm2 = VirtualMachine.objects.get(id=vm.id) |
|
104 |
self.assertEqual(vm2.backend, None) |
|
105 |
# Test tha backend networks are deleted, but not the network |
|
106 |
self.assertRaises(BackendNetwork.DoesNotExist, |
|
107 |
BackendNetwork.objects.get, id=bnet.id) |
|
108 |
Network.objects.get(id=bnet.network.id) |
|
109 |
|
|
110 |
def test_delete_active_backend(self): |
|
111 |
"""Test that a backend with non-deleted VMS is not deleted""" |
|
112 |
mfact.VirtualMachineFactory(backend=self.backend) |
|
113 |
self.assertRaises(IntegrityError, self.backend.delete, ()) |
|
114 |
|
|
115 |
def test_password_encryption(self): |
|
116 |
password_hash = self.backend.password |
|
117 |
self.backend.password = '123' |
|
118 |
self.assertNotEqual(self.backend.password_hash, '123') |
|
119 |
self.assertNotEqual(self.backend.password_hash, password_hash) |
|
120 |
self.assertEqual(self.backend.password, '123') |
|
121 |
|
|
122 |
|
|
123 |
class VirtualMachineTest(TestCase): |
|
124 |
def setUp(self): |
|
125 |
self.vm = mfact.VirtualMachineFactory() |
|
126 |
|
|
127 |
@patch("synnefo.db.models.get_rapi_client") |
|
128 |
def test_get_client(self, client): |
|
129 |
backend = self.vm.backend |
|
130 |
id_ = backend.id |
|
131 |
hash_ = backend.hash |
|
132 |
name = backend.clustername |
|
133 |
passwd = backend.password |
|
134 |
user = backend.username |
|
135 |
port = backend.port |
|
136 |
self.vm.get_client() |
|
137 |
client.assert_called_once_with(id_, hash_, name, port, user, passwd) |
|
138 |
|
|
139 |
def test_create(self): |
|
140 |
vm = mfact.VirtualMachineFactory() |
|
141 |
self.assertEqual(vm.action, None) |
|
142 |
self.assertEqual(vm.backendjobid, None) |
|
143 |
self.assertEqual(vm.backendjobstatus, None) |
|
144 |
self.assertEqual(vm.backendopcode, None) |
|
145 |
self.assertEqual(vm.backendlogmsg, None) |
|
146 |
self.assertEqual(vm.operstate, 'BUILD') |
|
147 |
|
|
148 |
|
|
149 |
class NetworkTest(TestCase): |
|
150 |
def setUp(self): |
|
151 |
self.net = mfact.NetworkFactory() |
|
152 |
|
|
153 |
def test_tags(self): |
|
154 |
net1 = mfact.NetworkFactory(flavor='IP_LESS_ROUTED') |
|
155 |
self.assertEqual(net1.backend_tag, ['ip-less-routed']) |
|
156 |
net1 = mfact.NetworkFactory(flavor='CUSTOM') |
|
157 |
self.assertEqual(net1.backend_tag, []) |
|
158 |
|
|
159 |
def test_create_backend_network(self): |
|
160 |
len_backends = len(Backend.objects.all()) |
|
161 |
back = mfact.BackendFactory() |
|
162 |
self.net.create_backend_network(backend=back) |
|
163 |
BackendNetwork.objects.get(network=self.net, backend=back) |
|
164 |
back1 = mfact.BackendFactory() |
|
165 |
back2 = mfact.BackendFactory() |
|
166 |
self.net.create_backend_network() |
|
167 |
BackendNetwork.objects.get(network=self.net, backend=back1) |
|
168 |
BackendNetwork.objects.get(network=self.net, backend=back2) |
|
169 |
self.assertEqual(len(BackendNetwork.objects.filter(network=self.net)), |
|
170 |
len_backends + 3) |
|
171 |
|
|
172 |
def test_pool(self): |
|
173 |
pool = self.net.get_pool() |
|
174 |
pool.network = self.net |
|
175 |
self.assertTrue(isinstance(pool, IPPool)) |
|
176 |
|
|
177 |
def test_reserve_ip(self): |
|
178 |
net1 = mfact.NetworkFactory(subnet='192.168.2.0/24') |
|
179 |
net1.reserve_address('192.168.2.12') |
|
180 |
pool = net1.get_pool() |
|
181 |
self.assertFalse(pool.is_available('192.168.2.12')) |
|
182 |
net1.release_address('192.168.2.12') |
|
183 |
pool = net1.get_pool() |
|
184 |
self.assertTrue(pool.is_available('192.168.2.12')) |
|
185 |
|
|
186 |
|
|
187 |
class BackendNetworkTest(TestCase): |
|
188 |
def test_mac_prefix(self): |
|
189 |
network = mfact.NetworkFactory(mac_prefix='aa:bb:c') |
|
190 |
backend = mfact.BackendFactory() |
|
191 |
bnet = mfact.BackendNetworkFactory(network=network, backend=backend) |
|
192 |
self.assertTrue(backend.index < 10) |
|
193 |
self.assertEqual(bnet.mac_prefix, 'aa:bb:c%s' % backend.index) |
|
194 |
|
|
195 |
|
|
196 |
class BridgePoolTest(TestCase): |
|
197 |
def test_no_pool(self): |
|
198 |
self.assertRaises(BridgePoolTable.DoesNotExist, |
|
199 |
BridgePoolTable.get_pool) |
|
200 |
|
|
201 |
def test_two_pools(self): |
|
202 |
mfact.BridgePoolTableFactory() |
|
203 |
mfact.BridgePoolTableFactory() |
|
204 |
self.assertRaises(MultipleObjectsReturned, BridgePoolTable.get_pool) |
|
40 | 205 |
|
41 |
class FlavorTestCase(TestCase): |
|
42 |
fixtures = [ 'db_test_data' ] |
|
43 | 206 |
|
44 |
def test_flavor(self): |
|
45 |
"""Test a flavor object, its internal cost calculation and naming methods""" |
|
46 |
flavor = Flavor.objects.get(pk=30000) |
|
207 |
class AESTest(TestCase): |
|
208 |
def test_encrypt_decrtypt(self): |
|
209 |
from synnefo.db import aes_encrypt as aes |
|
210 |
old = 'bar' |
|
211 |
new = aes.decrypt_db_charfield(aes.encrypt_db_charfield(old)) |
|
212 |
self.assertEqual(old, new) |
|
47 | 213 |
|
48 |
# test name property, should be C1R1024D10 |
|
49 |
f_name = flavor.name |
|
214 |
def test_password_change(self): |
|
215 |
from synnefo.db import aes_encrypt as aes |
|
216 |
old_pass = aes.SECRET_ENCRYPTION_KEY |
|
217 |
old = 'bar' |
|
218 |
encrypted = aes.encrypt_db_charfield(old) |
|
219 |
aes.SECRET_ENCRYPTION_KEY = 'foo2' |
|
220 |
self.assertRaises(aes.CorruptedPassword, aes.decrypt_db_charfield, |
|
221 |
encrypted) |
|
222 |
aes.SECRET_ENCRYPTION_KEY = old_pass |
|
223 |
new = aes.decrypt_db_charfield(encrypted) |
|
224 |
self.assertEqual(old, new) |
|
50 | 225 |
|
51 |
self.assertEqual(f_name, 'C1R1024D10', 'flavor.name is not generated correctly, C1R1024D10! (%s)' % (f_name,)) |
|
226 |
def test_big_secret(self): |
|
227 |
from synnefo.db import aes_encrypt as aes |
|
228 |
old = aes.SECRET_ENCRYPTION_KEY |
|
229 |
aes.SECRET_ENCRYPTION_KEY = \ |
|
230 |
'91490231234814234812348913289481294812398421893489' |
|
231 |
self.assertRaises(ValueError, aes.encrypt_db_charfield, 'la') |
|
232 |
aes.SECRET_ENCRYPTION_KEY = old |
b/snf-cyclades-app/synnefo/logic/tests.py | ||
---|---|---|
43 | 43 |
from datetime import datetime |
44 | 44 |
from mock import patch |
45 | 45 |
from synnefo.api.util import allocate_resource |
46 |
from synnefo.logic.callbacks import update_db, update_net, update_network |
|
46 |
from synnefo.logic.callbacks import (update_db, update_net, update_network, |
|
47 |
update_build_progress) |
|
47 | 48 |
|
48 | 49 |
now = datetime.now |
49 | 50 |
from time import time |
... | ... | |
428 | 429 |
self.assertFalse(pool.is_reserved('10.0.0.20')) |
429 | 430 |
|
430 | 431 |
|
431 |
class ProcessOpStatusTestCase(TestCase): |
|
432 |
fixtures = ['db_test_data'] |
|
433 |
msg_op = { |
|
434 |
'instance': 'instance-name', |
|
435 |
'type': 'ganeti-op-status', |
|
436 |
'operation': 'OP_INSTANCE_STARTUP', |
|
437 |
'jobId': 0, |
|
438 |
'status': 'success', |
|
439 |
'logmsg': 'unittest - simulated message' |
|
440 |
} |
|
441 |
|
|
442 |
def test_op_startup_success(self): |
|
443 |
"""Test notification for successful OP_INSTANCE_START""" |
|
444 |
msg = self.msg_op |
|
445 |
msg['operation'] = 'OP_INSTANCE_STARTUP' |
|
446 |
msg['status'] = 'success' |
|
447 |
|
|
448 |
# This machine is initially in BUILD |
|
449 |
vm = VirtualMachine.objects.get(pk=30002) |
|
450 |
backend.process_op_status(vm, now(), msg["jobId"], msg["operation"], |
|
451 |
msg["status"], msg["logmsg"]) |
|
452 |
self.assertEquals(get_rsapi_state(vm), 'ACTIVE') |
|
453 |
|
|
454 |
def test_op_shutdown_success(self): |
|
455 |
"""Test notification for successful OP_INSTANCE_SHUTDOWN""" |
|
456 |
msg = self.msg_op |
|
457 |
msg['operation'] = 'OP_INSTANCE_SHUTDOWN' |
|
458 |
msg['status'] = 'success' |
|
459 |
|
|
460 |
# This machine is initially in BUILD |
|
461 |
vm = VirtualMachine.objects.get(pk=30002) |
|
462 |
backend.process_op_status(vm, now(), msg["jobId"], msg["operation"], |
|
463 |
msg["status"], msg["logmsg"]) |
|
464 |
self.assertEquals(get_rsapi_state(vm), 'STOPPED') |
|
465 |
|
|
466 |
def test_op_reboot_success(self): |
|
467 |
"""Test notification for successful OP_INSTANCE_REBOOT""" |
|
468 |
msg = self.msg_op |
|
469 |
msg['operation'] = 'OP_INSTANCE_REBOOT' |
|
470 |
msg['status'] = 'success' |
|
471 |
|
|
472 |
# This machine is initially in BUILD |
|
473 |
vm = VirtualMachine.objects.get(pk=30002) |
|
474 |
backend.process_op_status(vm, now(), msg["jobId"], msg["operation"], |
|
475 |
msg["status"], msg["logmsg"]) |
|
476 |
self.assertEquals(get_rsapi_state(vm), 'ACTIVE') |
|
432 |
@patch('synnefo.lib.amqp.AMQPClient') |
|
433 |
class UpdateBuildProgressTest(TestCase): |
|
434 |
def setUp(self): |
|
435 |
self.vm = mfactory.VirtualMachineFactory() |
|
477 | 436 |
|
478 |
def test_op_create_success(self): |
|
479 |
"""Test notification for successful OP_INSTANCE_CREATE""" |
|
480 |
msg = self.msg_op |
|
481 |
msg['operation'] = 'OP_INSTANCE_CREATE' |
|
482 |
msg['status'] = 'success' |
|
437 |
def get_db_vm(self): |
|
438 |
return VirtualMachine.objects.get(id=self.vm.id) |
|
483 | 439 |
|
484 |
# This machine is initially in BUILD |
|
485 |
vm = VirtualMachine.objects.get(pk=30002) |
|
486 |
backend.process_op_status(vm, now(), msg["jobId"], msg["operation"], |
|
487 |
msg["status"], msg["logmsg"]) |
|
488 |
self.assertEquals(get_rsapi_state(vm), 'ACTIVE') |
|
440 |
def create_msg(self, **kwargs): |
|
441 |
"""Create snf-progress-monitor message""" |
|
442 |
msg = {'event_time': split_time(time())} |
|
443 |
msg['type'] = 'image-copy-progress' |
|
444 |
msg['progress'] = 0 |
|
445 |
for key, val in kwargs.items(): |
|
446 |
msg[key] = val |
|
447 |
message = {'body': json.dumps(msg)} |
|
448 |
return message |
|
489 | 449 |
|
490 |
def test_op_remove_success(self): |
|
491 |
"""Test notification for successful OP_INSTANCE_REMOVE""" |
|
492 |
msg = self.msg_op |
|
493 |
msg['operation'] = 'OP_INSTANCE_REMOVE' |
|
494 |
msg['status'] = 'success' |
|
450 |
def test_missing_attribute(self, client): |
|
451 |
update_build_progress(client, json.dumps({'body': {}})) |
|
452 |
client.basic_nack.assert_called_once() |
|
495 | 453 |
|
496 |
# This machine is initially in BUILD |
|
497 |
vm = VirtualMachine.objects.get(pk=30002) |
|
498 |
backend.process_op_status(vm, now(), msg["jobId"], msg["operation"], |
|
499 |
msg["status"], msg["logmsg"]) |
|
500 |
self.assertEquals(get_rsapi_state(vm), 'DELETED') |
|
501 |
self.assertTrue(vm.deleted) |
|
502 |
|
|
503 |
def test_op_create_error(self): |
|
504 |
"""Test notification for failed OP_INSTANCE_CREATE""" |
|
505 |
msg = self.msg_op |
|
506 |
msg['operation'] = 'OP_INSTANCE_CREATE' |
|
507 |
msg['status'] = 'error' |
|
508 |
|
|
509 |
# This machine is initially in BUILD |
|
510 |
vm = VirtualMachine.objects.get(pk=30002) |
|
511 |
backend.process_op_status(vm, now(), msg["jobId"], msg["operation"], |
|
512 |
msg["status"], msg["logmsg"]) |
|
513 |
self.assertEquals(get_rsapi_state(vm), 'ERROR') |
|
514 |
self.assertFalse(vm.deleted) |
|
515 |
|
|
516 |
def test_remove_machine_in_error(self): |
|
517 |
"""Test notification for failed OP_INSTANCE_REMOVE, server in ERROR""" |
|
518 |
msg = self.msg_op |
|
519 |
msg['operation'] = 'OP_INSTANCE_REMOVE' |
|
520 |
msg['status'] = 'error' |
|
521 |
|
|
522 |
# This machine is initially in BUILD |
|
523 |
vm = VirtualMachine.objects.get(pk=30002) |
|
524 |
backend.process_op_status(vm, now(), 0, "OP_INSTANCE_CREATE", "error", "test") |
|
525 |
self.assertEquals(get_rsapi_state(vm), 'ERROR') |
|
526 |
|
|
527 |
backend.process_op_status(vm, now(), msg["jobId"], msg["operation"], |
|
528 |
msg["status"], msg["logmsg"]) |
|
529 |
self.assertEquals(get_rsapi_state(vm), 'DELETED') |
|
530 |
self.assertTrue(vm.deleted) |
|
531 |
|
|
532 |
|
|
533 |
class ProcessNetStatusTestCase(TestCase): |
|
534 |
fixtures = ['db_test_data'] |
|
454 |
def test_unhandled_exception(self, client): |
|
455 |
update_build_progress(client, {}) |
|
456 |
client.basic_reject.assert_called_once() |
|
535 | 457 |
|
536 |
def test_set_ipv4(self): |
|
537 |
"""Test reception of a net status notification""" |
|
538 |
msg = {'instance': 'instance-name', |
|
539 |
'type': 'ganeti-net-status', |
|
540 |
'nics': [ |
|
541 |
{'ip': '10.0.0.21', |
|
542 |
'mac': 'aa:00:00:58:1e:b9', |
|
543 |
'network':'snf-net-30000'} |
|
544 |
] |
|
545 |
} |
|
546 |
vm = VirtualMachine.objects.get(pk=30000) |
|
547 |
backend.process_net_status(vm, now(), msg['nics']) |
|
548 |
self.assertEquals(vm.nics.all()[0].ipv4, '10.0.0.21') |
|
549 |
|
|
550 |
def test_set_empty_ipv4(self): |
|
551 |
"""Test reception of a net status notification with no IPv4 assigned""" |
|
552 |
msg = {'instance': 'instance-name', |
|
553 |
'type': 'ganeti-net-status', |
|
554 |
'nics': [ |
|
555 |
{'ip': '', |
|
556 |
'mac': 'aa:00:00:58:1e:b9', |
|
557 |
'network':'snf-net-30000'} |
|
558 |
] |
|
559 |
} |
|
560 |
vm = VirtualMachine.objects.get(pk=30000) |
|
561 |
backend.process_net_status(vm, now(), msg['nics']) |
|
562 |
self.assertEquals(vm.nics.all()[0].ipv4, '') |
|
563 |
|
|
564 |
|
|
565 |
class ProcessProgressUpdateTestCase(TestCase): |
|
566 |
fixtures = ['db_test_data'] |
|
458 |
def test_missing_instance(self, client): |
|
459 |
msg = self.create_msg(instance='foo') |
|
460 |
update_build_progress(client, msg) |
|
461 |
client.basic_nack.assert_called_once() |
|
567 | 462 |
|
568 |
def test_progress_update(self): |
|
569 |
"""Test reception of a create progress notification""" |
|
463 |
def test_wrong_type(self, client): |
|
464 |
msg = self.create_msg(type="WRONG_TYPE") |
|
465 |
update_build_progress(client, msg) |
|
466 |
client.basic_ack.assert_called_once() |
|
570 | 467 |
|
571 |
# This machine is in BUILD |
|
572 |
vm = VirtualMachine.objects.get(pk=30002) |
|
468 |
def test_progress_update(self, client): |
|
573 | 469 |
rprogress = randint(10, 100) |
574 |
|
|
575 |
backend.process_create_progress(vm, now(), rprogress) |
|
576 |
self.assertEquals(vm.buildpercentage, rprogress) |
|
577 |
|
|
578 |
#self.assertRaises(ValueError, backend.process_create_progress, |
|
579 |
# vm, 9, 0) |
|
580 |
self.assertRaises(ValueError, backend.process_create_progress, |
|
581 |
now(), vm, -1) |
|
582 |
self.assertRaises(ValueError, backend.process_create_progress, |
|
583 |
now(), vm, 'a') |
|
584 |
|
|
585 |
# This machine is ACTIVE |
|
586 |
#vm = VirtualMachine.objects.get(pk=30000) |
|
587 |
#self.assertRaises(VirtualMachine.IllegalState, |
|
588 |
# backend.process_create_progress, vm, 1) |
|
470 |
msg = self.create_msg(progress=rprogress, |
|
471 |
instance=self.vm.backend_vm_id) |
|
472 |
update_build_progress(client, msg) |
|
473 |
client.basic_ack.assert_called_once() |
|
474 |
vm = self.get_db_vm() |
|
475 |
self.assertEqual(vm.buildpercentage, rprogress) |
|
476 |
|
|
477 |
def test_invalid_value(self, client): |
|
478 |
old = self.vm.buildpercentage |
|
479 |
for rprogress in [0, -1, 'a']: |
|
480 |
msg = self.create_msg(progress=rprogress, |
|
481 |
instance=self.vm.backend_vm_id) |
|
482 |
update_build_progress(client, msg) |
|
483 |
client.basic_ack.assert_called_once() |
|
484 |
vm = self.get_db_vm() |
|
485 |
self.assertEqual(vm.buildpercentage, old) |
|
589 | 486 |
|
590 | 487 |
|
591 |
class ReconciliationTestCase(TestCase):
|
|
488 |
class ReconciliationTest(TestCase): |
|
592 | 489 |
SERVERS = 1000 |
593 | 490 |
fixtures = ['db_test_data'] |
594 | 491 |
|
595 | 492 |
def test_get_servers_from_db(self): |
596 | 493 |
"""Test getting a dictionary from each server to its operstate""" |
597 |
reconciliation.get_servers_from_db() |
|
598 | 494 |
self.assertEquals(reconciliation.get_servers_from_db(), |
599 | 495 |
{30000: 'STARTED', 30001: 'STOPPED', 30002: 'BUILD'}) |
600 | 496 |
|
... | ... | |
607 | 503 |
self.assertEquals(reconciliation.stale_servers_in_db(D, G), |
608 | 504 |
set([2, 30002])) |
609 | 505 |
|
506 |
@patch("synnefo.db.models.get_rapi_client") |
|
507 |
def test_stale_building_vm(self, client): |
|
508 |
vm = mfactory.VirtualMachineFactory() |
|
509 |
vm.state = 'BUILD' |
|
510 |
vm.backendjobid = 42 |
|
511 |
vm.save() |
|
512 |
D = {vm.id: 'BUILD'} |
|
513 |
G = {} |
|
514 |
for status in ['queued', 'waiting', 'running']: |
|
515 |
client.return_value.GetJobStatus.return_value = {'status': status} |
|
516 |
self.assertEqual(reconciliation.stale_servers_in_db(D, G), set([])) |
|
517 |
client.return_value.GetJobStatus.assert_called_once_with(vm.backendjobid) |
|
518 |
client.reset_mock() |
|
519 |
for status in ['success', 'error', 'canceled']: |
|
520 |
client.return_value.GetJobStatus.return_value = {'status': status} |
|
521 |
self.assertEqual(reconciliation.stale_servers_in_db(D, G), set([])) |
|
522 |
client.return_value.GetInstance.assert_called_once_with(vm.backend_vm_id) |
|
523 |
client.return_value.GetJobStatus.assert_called_once_with(vm.backendjobid) |
|
524 |
client.reset_mock() |
|
525 |
from synnefo.logic.rapi import GanetiApiError |
|
526 |
client.return_value.GetJobStatus.side_effect = GanetiApiError('Foo') |
|
527 |
self.assertEqual(reconciliation.stale_servers_in_db(D, G), set([vm.id])) |
|
528 |
|
|
610 | 529 |
def test_orphan_instances_in_ganeti(self): |
611 | 530 |
"""Test discovery of orphan instances in Ganeti, without a DB entry""" |
612 | 531 |
|
Also available in: Unified diff