Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / tests.py @ 2e1e6844

History | View | Annotate | Download (9.3 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 reconciliation
43
from synnefo.logic.utils import get_rsapi_state
44

    
45

    
46
class ProcessOpStatusTestCase(TestCase):
47
    fixtures = ['db_test_data']
48
    msg_op = {
49
        'instance': 'instance-name',
50
        'type': 'ganeti-op-status',
51
        'operation': 'OP_INSTANCE_STARTUP',
52
        'jobId': 0,
53
        'status': 'success',
54
        'logmsg': 'unittest - simulated message'
55
    }
56

    
57
    def test_op_startup_success(self):
58
        """Test notification for successful OP_INSTANCE_START"""
59
        msg = self.msg_op
60
        msg['operation'] = 'OP_INSTANCE_STARTUP'
61
        msg['status'] = 'success'
62

    
63
        # This machine is initially in BUILD
64
        vm = VirtualMachine.objects.get(pk=30002)
65
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
66
                                  msg["status"], msg["logmsg"])
67
        self.assertEquals(get_rsapi_state(vm), 'ACTIVE')
68

    
69
    def test_op_shutdown_success(self):
70
        """Test notification for successful OP_INSTANCE_SHUTDOWN"""
71
        msg = self.msg_op
72
        msg['operation'] = 'OP_INSTANCE_SHUTDOWN'
73
        msg['status'] = 'success'
74

    
75
        # This machine is initially in BUILD
76
        vm = VirtualMachine.objects.get(pk=30002)
77
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
78
                                  msg["status"], msg["logmsg"])
79
        self.assertEquals(get_rsapi_state(vm), 'STOPPED')
80

    
81
    def test_op_reboot_success(self):
82
        """Test notification for successful OP_INSTANCE_REBOOT"""
83
        msg = self.msg_op
84
        msg['operation'] = 'OP_INSTANCE_REBOOT'
85
        msg['status'] = 'success'
86

    
87
        # This machine is initially in BUILD
88
        vm = VirtualMachine.objects.get(pk=30002)
89
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
90
                                  msg["status"], msg["logmsg"])
91
        self.assertEquals(get_rsapi_state(vm), 'ACTIVE')
92

    
93
    def test_op_create_success(self):
94
        """Test notification for successful OP_INSTANCE_CREATE"""
95
        msg = self.msg_op
96
        msg['operation'] = 'OP_INSTANCE_CREATE'
97
        msg['status'] = 'success'
98

    
99
        # This machine is initially in BUILD
100
        vm = VirtualMachine.objects.get(pk=30002)
101
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
102
                                  msg["status"], msg["logmsg"])
103
        self.assertEquals(get_rsapi_state(vm), 'ACTIVE')
104

    
105
    def test_op_remove_success(self):
106
        """Test notification for successful OP_INSTANCE_REMOVE"""
107
        msg = self.msg_op
108
        msg['operation'] = 'OP_INSTANCE_REMOVE'
109
        msg['status'] = 'success'
110

    
111
        # This machine is initially in BUILD
112
        vm = VirtualMachine.objects.get(pk=30002)
113
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
114
                                  msg["status"], msg["logmsg"])
115
        self.assertEquals(get_rsapi_state(vm), 'DELETED')
116
        self.assertTrue(vm.deleted)
117

    
118
    def test_op_create_error(self):
119
        """Test notification for failed OP_INSTANCE_CREATE"""
120
        msg = self.msg_op
121
        msg['operation'] = 'OP_INSTANCE_CREATE'
122
        msg['status'] = 'error'
123

    
124
        # This machine is initially in BUILD
125
        vm = VirtualMachine.objects.get(pk=30002)
126
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
127
                                  msg["status"], msg["logmsg"])
128
        self.assertEquals(get_rsapi_state(vm), 'ERROR')
129
        self.assertFalse(vm.deleted)
130

    
131
    def test_remove_machine_in_error(self):
132
        """Test notification for failed OP_INSTANCE_REMOVE, server in ERROR"""
133
        msg = self.msg_op
134
        msg['operation'] = 'OP_INSTANCE_REMOVE'
135
        msg['status'] = 'error'
136

    
137
        # This machine is initially in BUILD
138
        vm = VirtualMachine.objects.get(pk=30002)
139
        backend.process_op_status(vm, 0, "OP_INSTANCE_CREATE", "error", "test")
140
        self.assertEquals(get_rsapi_state(vm), 'ERROR')
141

    
142
        backend.process_op_status(vm, msg["jobId"], msg["operation"],
143
                                  msg["status"], msg["logmsg"])
144
        self.assertEquals(get_rsapi_state(vm), 'DELETED')
145
        self.assertTrue(vm.deleted)
146

    
147

    
148
class ProcessNetStatusTestCase(TestCase):
149
    fixtures = ['db_test_data']
150

    
151
    def test_set_ipv4(self):
152
        """Test reception of a net status notification"""
153
        msg = {'instance': 'instance-name',
154
               'type':     'ganeti-net-status',
155
               'nics': [
156
                   {'ip': '192.168.33.1', 'mac': 'aa:00:00:58:1e:b9'}
157
               ]
158
        }
159
        vm = VirtualMachine.objects.get(pk=30000)
160
        backend.process_net_status(vm, msg['nics'])
161
        self.assertEquals(vm.nics.all()[0].ipv4, '192.168.33.1')
162

    
163
    def test_set_empty_ipv4(self):
164
        """Test reception of a net status notification with no IPv4 assigned"""
165
        msg = {'instance': 'instance-name',
166
               'type':     'ganeti-net-status',
167
               'nics': [
168
                   {'ip': '', 'mac': 'aa:00:00:58:1e:b9'}
169
               ]
170
        }
171
        vm = VirtualMachine.objects.get(pk=30000)
172
        backend.process_net_status(vm, msg['nics'])
173
        self.assertEquals(vm.nics.all()[0].ipv4, '')
174

    
175

    
176
class ProcessProgressUpdateTestCase(TestCase):
177
    fixtures = ['db_test_data']
178

    
179
    def test_progress_update(self):
180
        """Test reception of a create progress notification"""
181

    
182
        # This machine is in BUILD
183
        vm = VirtualMachine.objects.get(pk=30002)
184
        rprogress = randint(10, 100)
185

    
186
        backend.process_create_progress(vm, rprogress, 0)
187
        self.assertEquals(vm.buildpercentage, rprogress)
188

    
189
        #self.assertRaises(ValueError, backend.process_create_progress,
190
        #                  vm, 9, 0)
191
        self.assertRaises(ValueError, backend.process_create_progress,
192
                          vm, -1, 0)
193
        self.assertRaises(ValueError, backend.process_create_progress,
194
                          vm, 'a', 0)
195

    
196
        # This machine is ACTIVE
197
        #vm = VirtualMachine.objects.get(pk=30000)
198
        #self.assertRaises(VirtualMachine.IllegalState,
199
        #                  backend.process_create_progress, vm, 1)
200

    
201

    
202
class ReconciliationTestCase(TestCase):
203
    SERVERS = 1000
204
    fixtures = ['db_test_data']
205

    
206
    def test_get_servers_from_db(self):
207
        """Test getting a dictionary from each server to its operstate"""
208
        reconciliation.get_servers_from_db()
209
        self.assertEquals(reconciliation.get_servers_from_db(),
210
                          {30000: 'STARTED', 30001: 'STOPPED', 30002: 'BUILD'})
211

    
212
    def test_stale_servers_in_db(self):
213
        """Test discovery of stale entries in DB"""
214

    
215
        D = {1: 'STARTED', 2: 'STOPPED', 3: 'STARTED', 4: 'BUILD', 5: 'BUILD'}
216
        G = {1: True, 3: True}
217
        self.assertEquals(reconciliation.stale_servers_in_db(D, G),
218
                          set([2, 4, 5]))
219

    
220
    def test_orphan_instances_in_ganeti(self):
221
        """Test discovery of orphan instances in Ganeti, without a DB entry"""
222

    
223
        G = {1: True, 2: False, 3: False, 4: True, 50: True}
224
        D = {1: True, 3: False}
225
        self.assertEquals(reconciliation.orphan_instances_in_ganeti(D, G),
226
                          set([2, 4, 50]))
227

    
228
    def test_unsynced_operstate(self):
229
        """Test discovery of unsynced operstate between the DB and Ganeti"""
230

    
231
        G = {1: True, 2: False, 3: True, 4: False, 50: True}
232
        D = {1: 'STARTED', 2: 'STARTED', 3: 'BUILD', 4: 'STARTED', 50: 'BUILD'}
233
        self.assertEquals(reconciliation.unsynced_operstate(D, G),
234
                          set([(2, 'STARTED', False),
235
                           (3, 'BUILD', True), (4, 'STARTED', False),
236
                           (50, 'BUILD', True)]))