Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (20.3 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 vigilo.models.tables.grouphierarchy import GroupHierarchy
23
from vigiboard.tests import TestController
24

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

    
32
    DBSession.add(GroupHierarchy(
33
        parent=supitemmanagers,
34
        child=supitemmanagers,
35
        hops=0,
36
    ))
37
    DBSession.flush()
38

    
39
    usergroup = UserGroup.by_group_name(u'users_with_access')
40
    DBSession.add(DataPermission(
41
        group=supitemmanagers,
42
        usergroup=usergroup,
43
        access=u'w',
44
    ))
45
    DBSession.flush()
46

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

    
72
    # On crée 2 services de bas niveau, et on les ajoute au groupe de services.
73
    service1 = LowLevelService(
74
        host = host1,
75
        servicename = u'service1',
76
        command = u'halt',
77
        op_dep = u'+',
78
        weight = 42,
79
    )
80
    DBSession.add(service1)
81
    supitemmanagers.supitems.append(service1)
82
    service2 = LowLevelService(
83
        host = host2,
84
        servicename = u'service2',
85
        command = u'halt',
86
        op_dep = u'+',
87
        weight = 42,
88
    )
89
    DBSession.add(service2)
90
    supitemmanagers.supitems.append(service2)
91
    DBSession.flush()
92
    
93
    return ([host1, host2], [service1, service2])
94

    
95
def add_correvent_caused_by(supitem, timestamp,
96
        correvent_status=u"None", event_status=u"WARNING"):
97
    """
98
    Ajoute dans la base de données un évènement corrélé causé 
99
    par un incident survenu sur l'item passé en paramètre.
100
    Génère un historique pour les tests.
101
    """
102

    
103
    # Ajout d'un événement
104
    event = Event(
105
        supitem = supitem, 
106
        message = u'foo',
107
        current_state = StateName.statename_to_value(event_status),
108
        timestamp = datetime.now(),
109
    )
110
    DBSession.add(event)
111
    DBSession.flush()
112

    
113
    # Ajout d'un événement corrélé
114
    aggregate = CorrEvent(
115
        idcause = event.idevent, 
116
        timestamp_active = timestamp,
117
        priority = 1,
118
        status = correvent_status)
119
    aggregate.events.append(event)
120
    DBSession.add(aggregate)
121
    DBSession.flush()
122
    
123
    return aggregate.idcorrevent
124

    
125

    
126
class TestRootController(TestController):
127
    """ Classe de test du root controller """
128
    def setUp(self):
129
        super(TestRootController, self).setUp()
130
        perm = Permission.by_permission_name(u'vigiboard-access')
131
        perm2 = Permission.by_permission_name(u'vigiboard-update')
132

    
133
        user = User(
134
            user_name=u'access',
135
            fullname=u'',
136
            email=u'user.has@access',
137
        )
138
        usergroup = UserGroup(
139
            group_name=u'users_with_access',
140
        )
141
        usergroup.permissions.append(perm)
142
        usergroup.permissions.append(perm2)
143
        user.usergroups.append(usergroup)
144
        DBSession.add(user)
145
        DBSession.add(usergroup)
146
        DBSession.flush()
147

    
148
        user = User(
149
            user_name=u'limited_access',
150
            fullname=u'',
151
            email=u'user.has.no@access',
152
        )
153
        usergroup = UserGroup(
154
            group_name=u'users_with_limited_access',
155
        )
156
        usergroup.permissions.append(perm)
157
        usergroup.permissions.append(perm2)
158
        user.usergroups.append(usergroup)
159
        DBSession.add(user)
160
        DBSession.add(usergroup)
161
        DBSession.flush()
162

    
163
    def test_index(self):
164
        """Test that access to the root webpage is restricted."""
165

    
166
        response = self.app.get('/', status=401)
167
        msg = 'Unauthorized'
168
        assert_true(msg in response)
169

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

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

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

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

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

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

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

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

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

    
388

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

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

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

    
462
    def test_update_while_data_have_changed(self):
463
        """Màj d'un évènement corrélé modifié entre temps."""
464

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