Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

vigiboard / vigiboard / tests / functional / test_root.py @ 0bd9c069

History | View | Annotate | Download (20 KB)

1
# -*- coding: utf-8 -*-
2
"""
3
Functional test suite for the root controller.
4

5
This is an example of how functional tests can be written for controllers.
6

7
As opposed to a unit-test, which test a small unit of functionality,
8
functional tests exercise the whole application and its WSGI stack.
9

10
Please read http://pythonpaste.org/webtest/ for more information.
11

12
"""
13
from nose.tools import assert_true, assert_false, assert_equal
14
from datetime import datetime
15
from time import mktime
16
import transaction
17

    
18
from vigilo.models.session import DBSession
19
from vigilo.models.tables import Event, EventHistory, CorrEvent, User, \
20
                            Permission, StateName, Host, UserGroup, \
21
                            SupItemGroup, LowLevelService, DataPermission
22
from vigiboard.tests import TestController
23

    
24
def populate_DB():
25
    """ Peuple la base de données. """
26
    # On ajoute un groupe d'hôtes et un groupe de services.
27
    supitemmanagers = SupItemGroup(name = u'managersgroup')
28
    DBSession.add(supitemmanagers)
29
    DBSession.flush()
30

    
31
    usergroup = UserGroup.by_group_name(u'users_with_access')
32
    DBSession.add(DataPermission(
33
        group=supitemmanagers,
34
        usergroup=usergroup,
35
        access=u'w',
36
    ))
37
    DBSession.flush()
38

    
39
    # On crée un 2 hôtes, et on les ajoute au groupe d'hôtes.
40
    host1 = Host(
41
        name = u'host1',      
42
        checkhostcmd = u'halt',
43
        snmpcommunity = u'public',
44
        hosttpl = u'/dev/null',
45
        address = u'192.168.1.1',
46
        snmpport = 42,
47
        weight = 42,
48
    )
49
    DBSession.add(host1)
50
    supitemmanagers.supitems.append(host1)
51
    host2 = Host(
52
        name = u'host2',      
53
        checkhostcmd = u'halt',
54
        snmpcommunity = u'public',
55
        hosttpl = u'/dev/null',
56
        address = u'192.168.1.1',
57
        snmpport = 42,
58
        weight = 42,
59
    )
60
    DBSession.add(host2)
61
    supitemmanagers.supitems.append(host2)
62
    DBSession.flush()
63

    
64
    # On crée 2 services de bas niveau, et on les ajoute au groupe de services.
65
    service1 = LowLevelService(
66
        host = host1,
67
        servicename = u'service1',
68
        command = u'halt',
69
        weight = 42,
70
    )
71
    DBSession.add(service1)
72
    supitemmanagers.supitems.append(service1)
73
    service2 = LowLevelService(
74
        host = host2,
75
        servicename = u'service2',
76
        command = u'halt',
77
        weight = 42,
78
    )
79
    DBSession.add(service2)
80
    supitemmanagers.supitems.append(service2)
81
    DBSession.flush()
82
    
83
    return ([host1, host2], [service1, service2])
84

    
85
def add_correvent_caused_by(supitem, timestamp,
86
        correvent_status=u"None", event_status=u"WARNING"):
87
    """
88
    Ajoute dans la base de données un évènement corrélé causé 
89
    par un incident survenu sur l'item passé en paramètre.
90
    Génère un historique pour les tests.
91
    """
92

    
93
    # Ajout d'un événement
94
    event = Event(
95
        supitem = supitem, 
96
        message = u'foo',
97
        current_state = StateName.statename_to_value(event_status),
98
        timestamp = datetime.now(),
99
    )
100
    DBSession.add(event)
101
    DBSession.flush()
102

    
103
    # Ajout d'un événement corrélé
104
    aggregate = CorrEvent(
105
        idcause = event.idevent, 
106
        timestamp_active = timestamp,
107
        priority = 1,
108
        status = correvent_status)
109
    aggregate.events.append(event)
110
    DBSession.add(aggregate)
111
    DBSession.flush()
112
    
113
    return aggregate.idcorrevent
114

    
115

    
116
class TestRootController(TestController):
117
    """ Classe de test du root controller """
118
    def setUp(self):
119
        super(TestRootController, self).setUp()
120
        perm = Permission.by_permission_name(u'vigiboard-access')
121
        perm2 = Permission.by_permission_name(u'vigiboard-update')
122

    
123
        user = User(
124
            user_name=u'access',
125
            fullname=u'',
126
            email=u'user.has@access',
127
        )
128
        usergroup = UserGroup(
129
            group_name=u'users_with_access',
130
        )
131
        usergroup.permissions.append(perm)
132
        usergroup.permissions.append(perm2)
133
        user.usergroups.append(usergroup)
134
        DBSession.add(user)
135
        DBSession.add(usergroup)
136
        DBSession.flush()
137

    
138
        user = User(
139
            user_name=u'limited_access',
140
            fullname=u'',
141
            email=u'user.has.no@access',
142
        )
143
        usergroup = UserGroup(
144
            group_name=u'users_with_limited_access',
145
        )
146
        usergroup.permissions.append(perm)
147
        usergroup.permissions.append(perm2)
148
        user.usergroups.append(usergroup)
149
        DBSession.add(user)
150
        DBSession.add(usergroup)
151
        DBSession.flush()
152

    
153
    def test_index(self):
154
        """Test that access to the root webpage is restricted."""
155

    
156
        response = self.app.get('/', status=401)
157
        msg = 'Unauthorized'
158
        assert_true(msg in response)
159

    
160
    def test_update_host_correvents_status(self):
161
        """Màj du statut d'évènements corrélés causés par des hôtes"""
162

    
163
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
164
        # et un groupe d'hôtes et de services associés à ces items.
165
        (hosts, services) = populate_DB()
166
        
167
        # On ajoute 2 évènements corrélés causés par ces hôtes
168
        timestamp = datetime.now()
169
        correvent1_id = add_correvent_caused_by(hosts[0], timestamp)
170
        correvent2_id = add_correvent_caused_by(hosts[1], timestamp)
171
        transaction.commit()
172
        
173
        ### 1er cas : L'utilisateur n'est pas connecté.
174
        # On vérifie que le plugin retourne bien une erreur 401.
175
        response = self.app.post(
176
            '/update', {
177
                "id" : str(correvent1_id) + "," + str(correvent2_id),
178
                "last_modification": mktime(timestamp.timetuple()),
179
                "trouble_ticket" : u"foo",
180
                "ack" : u'NoChange',
181
            }, status = 401)
182
        
183
        ### 2ème cas : L'utilisateur utilisé pour
184
        # se connecter à Vigiboard est 'limited_access'.
185
        environ = {'REMOTE_USER': 'limited_access'}
186
        
187
        # On s'attend à ce qu'une erreur 302 soit renvoyée, et à
188
        # ce qu'un message d'erreur précise à l'utilisateur qu'il
189
        # n'a pas la permission de modifier ces évènements.
190
        response = self.app.post(
191
            '/update', {
192
                "id" : str(correvent1_id) + "," + str(correvent2_id),
193
                "ack" : u'NoChange',
194
                "trouble_ticket" : u"foo",
195
                "last_modification": mktime(timestamp.timetuple()),
196
            }, status = 302, extra_environ = environ)
197
        
198
        response = response.follow(status=200, extra_environ = environ)
199
        assert_true(response.lxml.xpath(
200
            '//div[@id="flash"]/div[@class="error"]'))
201

    
202
        ### 3ème cas : L'utilisateur utilisé pour
203
        # se connecter à Vigiboard est 'access'.
204
        environ = {'REMOTE_USER': 'access'}
205
        
206
        # On s'attend à ce que le statut de la requête soit 302,
207
        # et à ce qu'un message informe l'utilisateur que les
208
        # évènements corrélés sélectionnées ont bien été mis à jour.
209
        response = self.app.post(
210
            '/update', {
211
                "id" : str(correvent1_id) + "," + str(correvent2_id),
212
                "last_modification": mktime(timestamp.timetuple()),
213
                "trouble_ticket" : u"foo",
214
                "ack" : u'NoChange',
215
            }, status = 302, extra_environ = environ)
216
        
217
        response = response.follow(status=200, extra_environ = environ)
218
        assert_false(response.lxml.xpath(
219
            '//div[@id="flash"]/div[@class="error"]'))
220
        assert_true(response.lxml.xpath(
221
            '//div[@id="flash"]/div[@class="ok"]'))
222
        
223
        # On s'assure que le ticket de l'évènement corrélé
224
        # a bien été mis à jour dans la base de données.
225
        correvents = DBSession.query(
226
            CorrEvent.trouble_ticket
227
            ).filter(CorrEvent.idcorrevent.in_([correvent1_id, correvent2_id])
228
            ).all()
229
        
230
        assert_equal(correvents[0].trouble_ticket, u"foo")
231
        assert_equal(correvents[1].trouble_ticket, u"foo")
232

    
233
    def test_update_service_correvents_status(self):
234
        """Màj du statut d'évènements corrélés causés par des SBN"""
235

    
236
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
237
        # et un groupe d'hôtes et de services associés à ces items.
238
        (hosts, services) = populate_DB()
239
        
240
        # On ajoute 2 évènements corrélés causés par ces hôtes
241
        timestamp = datetime.now()
242
        correvent1_id = add_correvent_caused_by(services[0], timestamp)
243
        correvent2_id = add_correvent_caused_by(services[1], timestamp)
244
        
245
        transaction.commit()
246
        
247
        ### 1er cas : L'utilisateur n'est pas connecté.
248
        # On vérifie que le plugin retourne bien une erreur 401.
249
        response = self.app.post(
250
            '/update', {
251
                "id" : str(correvent1_id) + "," + str(correvent2_id),
252
                "last_modification": mktime(timestamp.timetuple()),
253
                "trouble_ticket" : u"foo",
254
                "ack" : u'NoChange',
255
            }, status = 401)
256
        
257
        ### 2ème cas : L'utilisateur utilisé pour
258
        # se connecter à Vigiboard est 'limited_access'.
259
        environ = {'REMOTE_USER': 'limited_access'}
260
        
261
        # On s'attend à ce qu'une erreur 302 soit renvoyée, et à
262
        # ce qu'un message d'erreur précise à l'utilisateur qu'il
263
        # n'a pas la permission de modifier ces évènements.
264
        response = self.app.post(
265
            '/update', {
266
                "id" : str(correvent1_id) + "," + str(correvent2_id),
267
                "last_modification": mktime(timestamp.timetuple()),
268
                "trouble_ticket" : u"foo",
269
                "ack" : u'NoChange',
270
            }, status = 302, extra_environ = environ)
271
        
272
        response = response.follow(status=200, extra_environ = environ)
273
        assert_true(response.lxml.xpath(
274
            '//div[@id="flash"]/div[@class="error"]'))
275

    
276
        ### 3ème cas : L'utilisateur utilisé pour
277
        # se connecter à Vigiboard est 'access'.
278
        environ = {'REMOTE_USER': 'access'}
279
        
280
        # On s'attend à ce que le statut de la requête soit 302,
281
        # et à ce qu'un message informe l'utilisateur que les
282
        # évènements corrélés sélectionnées ont bien été mis à jour.
283
        response = self.app.post(
284
            '/update', {
285
                "id" : str(correvent1_id) + "," + str(correvent2_id),
286
                "last_modification": mktime(timestamp.timetuple()),
287
                "trouble_ticket" : u"foo",
288
                "ack" : u'NoChange',
289
            }, status = 302, extra_environ = environ)
290
        
291
        response = response.follow(status=200, extra_environ = environ)
292
        assert_false(response.lxml.xpath(
293
            '//div[@id="flash"]/div[@class="error"]'))
294
        assert_true(response.lxml.xpath(
295
            '//div[@id="flash"]/div[@class="ok"]'))
296
        
297
        # On s'assure que le ticket de l'évènement corrélé
298
        # a bien été mis à jour dans la base de données.
299
        correvents = DBSession.query(
300
            CorrEvent.trouble_ticket
301
            ).filter(CorrEvent.idcorrevent.in_([correvent1_id, correvent2_id])
302
            ).all()
303
        assert_equal(correvents[0].trouble_ticket, u"foo")
304
        assert_equal(correvents[1].trouble_ticket, u"foo")
305

    
306
    def test_update_host_correvents_tickets(self):
307
        """Màj de tickets d'évènements corrélés causés par des hôtes"""
308

    
309
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
310
        # et un groupe d'hôtes et de services associés à ces items.
311
        (hosts, services) = populate_DB()
312
        
313
        # On ajoute 2 évènements corrélés causés par ces hôtes
314
        timestamp = datetime.now()
315
        correvent1_id = add_correvent_caused_by(hosts[0], timestamp)
316
        correvent2_id = add_correvent_caused_by(hosts[1], timestamp)
317
        transaction.commit()
318
        
319
        ### 1er cas : L'utilisateur n'est pas connecté.
320
        # On vérifie que le plugin retourne bien une erreur 401.
321
        response = self.app.post(
322
            '/update', {
323
                "id" : str(correvent1_id) + "," + str(correvent2_id),
324
                "last_modification": mktime(timestamp.timetuple()),
325
                "trouble_ticket" : "",
326
                "ack" : u'Acknowledged',
327
            }, status = 401)
328
        
329
        ### 2ème cas : L'utilisateur utilisé pour
330
        # se connecter à Vigiboard est 'limited_access'.
331
        environ = {'REMOTE_USER': 'limited_access'}
332
        
333
        # On s'attend à ce qu'une erreur 302 soit renvoyée, et à
334
        # ce qu'un message d'erreur précise à l'utilisateur qu'il
335
        # n'a pas la permission de modifier ces évènements.
336
        response = self.app.post(
337
            '/update', {
338
                "id" : str(correvent1_id) + "," + str(correvent2_id),
339
                "last_modification": mktime(timestamp.timetuple()),
340
                "trouble_ticket" : "",
341
                "ack" : u'Acknowledged',
342
            }, status = 302, extra_environ = environ)
343
        
344
        response = response.follow(status=200, extra_environ = environ)
345
        assert_true(response.lxml.xpath(
346
            '//div[@id="flash"]/div[@class="error"]'))
347

    
348
        ### 3ème cas : L'utilisateur utilisé pour
349
        # se connecter à Vigiboard est 'access'.
350
        environ = {'REMOTE_USER': 'access'}
351
        
352
        # On s'attend à ce que le statut de la requête soit 302,
353
        # et à ce qu'un message informe l'utilisateur que les
354
        # évènements corrélés sélectionnées ont bien été mis à jour.
355
        response = self.app.post(
356
            '/update', {
357
                "id" : str(correvent1_id) + "," + str(correvent2_id),
358
                "last_modification": mktime(timestamp.timetuple()),
359
                "trouble_ticket" : "",
360
                "ack" : u'Acknowledged',
361
            }, status = 302, extra_environ = environ)
362
        
363
        response = response.follow(status=200, extra_environ = environ)
364
        assert_false(response.lxml.xpath(
365
            '//div[@id="flash"]/div[@class="error"]'))
366
        assert_true(response.lxml.xpath(
367
            '//div[@id="flash"]/div[@class="ok"]'))
368
        
369
        # On s'assure que le statut de l'évènement corrélé
370
        # a bien été mis à jour dans la base de données.
371
        correvents = DBSession.query(
372
            CorrEvent.status
373
            ).filter(CorrEvent.idcorrevent.in_([correvent1_id, correvent2_id])
374
            ).all()
375
        assert_equal(correvents[0].status, u'Acknowledged')
376
        assert_equal(correvents[1].status, u'Acknowledged')
377

    
378

    
379
    def test_update_service_correvents_tickets(self):
380
        """Màj de tickets d'évènements corrélés causés par des SBN"""
381

    
382
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
383
        # et un groupe d'hôtes et de services associés à ces items.
384
        (hosts, services) = populate_DB()
385
        
386
        # On ajoute 2 évènements corrélés causés par ces hôtes
387
        timestamp = datetime.now()
388
        correvent1_id = add_correvent_caused_by(services[0], timestamp)
389
        correvent2_id = add_correvent_caused_by(services[1], timestamp)
390
        
391
        transaction.commit()
392
        
393
        ### 1er cas : L'utilisateur n'est pas connecté.
394
        # On vérifie que le plugin retourne bien une erreur 401.
395
        response = self.app.post(
396
            '/update', {
397
                "id" : str(correvent1_id) + "," + str(correvent2_id),
398
                "last_modification": mktime(timestamp.timetuple()),
399
                "trouble_ticket" : "",
400
                "ack" : u'Acknowledged',
401
            }, status = 401)
402
        
403
        ### 2ème cas : L'utilisateur utilisé pour
404
        # se connecter à Vigiboard est 'limited_access'.
405
        environ = {'REMOTE_USER': 'limited_access'}
406
        
407
        # On s'attend à ce qu'une erreur 302 soit renvoyée, et à
408
        # ce qu'un message d'erreur précise à l'utilisateur qu'il
409
        # n'a pas la permission de modifier ces évènements.
410
        response = self.app.post(
411
            '/update', {
412
                "id" : str(correvent1_id) + "," + str(correvent2_id),
413
                "last_modification": mktime(timestamp.timetuple()),
414
                "trouble_ticket" : "",
415
                "ack" : u'Acknowledged',
416
            }, status = 302, extra_environ = environ)
417
        
418
        response = response.follow(status=200, extra_environ = environ)
419
        assert_true(response.lxml.xpath(
420
            '//div[@id="flash"]/div[@class="error"]'))
421

    
422
        ### 3ème cas : L'utilisateur utilisé pour
423
        # se connecter à Vigiboard est 'access'.
424
        environ = {'REMOTE_USER': 'access'}
425
        
426
        # On s'attend à ce que le statut de la requête soit 302,
427
        # et à ce qu'un message informe l'utilisateur que les
428
        # évènements corrélés sélectionnées ont bien été mis à jour.
429
        response = self.app.post(
430
            '/update', {
431
                "id" : str(correvent1_id) + "," + str(correvent2_id),
432
                "last_modification": mktime(timestamp.timetuple()),
433
                "trouble_ticket" : "",
434
                "ack" : u'Acknowledged',
435
            }, status = 302, extra_environ = environ)
436
        
437
        response = response.follow(status=200, extra_environ = environ)
438
        assert_false(response.lxml.xpath(
439
            '//div[@id="flash"]/div[@class="error"]'))
440
        assert_true(response.lxml.xpath(
441
            '//div[@id="flash"]/div[@class="ok"]'))
442
        
443
        # On s'assure que le statut de l'évènement corrélé
444
        # a bien été mis à jour dans la base de données.
445
        correvents = DBSession.query(
446
            CorrEvent.status
447
            ).filter(CorrEvent.idcorrevent.in_([correvent1_id, correvent2_id])
448
            ).all()
449
        assert_equal(correvents[0].status, u'Acknowledged')
450
        assert_equal(correvents[1].status, u'Acknowledged')
451

    
452
    def test_update_while_data_have_changed(self):
453
        """Màj d'un évènement corrélé modifié entre temps."""
454

    
455
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
456
        # et un groupe d'hôtes et de services associés à ces items.
457
        (hosts, services) = populate_DB()
458
        
459
        # On ajoute 2 évènements corrélés causés par ces hôtes
460
        timestamp = datetime.now()
461
        correvent1_id = add_correvent_caused_by(services[0], timestamp)
462
        correvent2_id = add_correvent_caused_by(services[1], timestamp)
463
        
464
        # Date de modification du premier évènement corrélé 
465
        later_date = datetime.now()
466
        # Date du chargement de la page
467
        date = mktime(later_date.timetuple()) - 42
468
        
469
        # On ajoute une entrée dans l'historique de l'évènement brut
470
        # causant le premier évènement corrélé, portant pour timestamp
471
        # une date postérieure à celle du chargement de la page.
472
        correvent1 = DBSession.query(
473
            CorrEvent.idcause
474
            ).filter(CorrEvent.idcorrevent == correvent1_id).one()
475
        DBSession.add(EventHistory(
476
            type_action = u'Nagios update state',
477
            idevent = correvent1.idcause,
478
            timestamp = later_date))
479
        DBSession.flush()
480
        
481
        transaction.commit()
482
        
483
        # L'utilisateur utilisé pour se connecter à Vigiboard est 'access'.
484
        environ = {'REMOTE_USER': 'access'}
485
        
486
        # On s'attend à ce que le statut de la requête soit 302, et
487
        # à ce qu'un message d'erreur avise l'utilisateur que des
488
        # changements sont intervenus depuis le chargement de la page.
489
        response = self.app.post(
490
            '/update', {
491
                "id" : str(correvent1_id),
492
                "last_modification" : date,
493
                "trouble_ticket" : "",
494
                "ack" : u'Acknowledged',
495
            }, status = 302, extra_environ = environ)
496
        
497
        response = response.follow(status=200, extra_environ = environ)
498
        assert_true(response.lxml.xpath(
499
            '//div[@id="flash"]/div[@class="warning"]'))
500
        
501
        # On s'assure que le statut de l'évènement corrélé
502
        # n'a pas été modifié dans la base de données.
503
        status = DBSession.query(
504
            CorrEvent.status
505
            ).filter(CorrEvent.idcorrevent == correvent1_id
506
            ).scalar()
507
        assert_equal(status, u'None')
508