Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

vigiboard / vigiboard / tests / functional / test_root.py @ 6f6efdcd

History | View | Annotate | Download (19.7 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
                            LowLevelService, DataPermission
22
from vigilo.models.demo.functions import *
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 = add_supitemgroup('managersgroup')
29
    DBSession.add(supitemmanagers)
30
    DBSession.flush()
31

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

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

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

    
84
    return ([host1, host2], [service1, service2])
85

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

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

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

    
114
    return aggregate.idcorrevent
115

    
116

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

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

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

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

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

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

    
164
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
165
        # et un groupe d'hôtes et de services associés à ces items.
166
        (hosts, services) = populate_DB()
167

    
168
        # On ajoute 2 évènements corrélés causés par ces hôtes
169
        timestamp = datetime.now()
170
        correvent1_id = add_correvent_caused_by(hosts[0], timestamp)
171
        correvent2_id = add_correvent_caused_by(hosts[1], timestamp)
172
        transaction.commit()
173

    
174
        ### 1er cas : L'utilisateur n'est pas connecté.
175
        # On vérifie que le plugin retourne bien une erreur 401.
176
        response = self.app.post(
177
            '/update', {
178
                "id" : str(correvent1_id) + "," + str(correvent2_id),
179
                "last_modification": mktime(timestamp.timetuple()),
180
                "trouble_ticket" : u"foo",
181
                "ack" : u'NoChange',
182
            }, status = 401)
183

    
184
        ### 2ème cas : L'utilisateur utilisé pour
185
        # se connecter à Vigiboard est 'limited_access'.
186
        environ = {'REMOTE_USER': 'limited_access'}
187

    
188
        # On s'attend à ce qu'une erreur 302 soit renvoyée, et à
189
        # ce qu'un message d'erreur précise à l'utilisateur qu'il
190
        # n'a pas la permission de modifier ces évènements.
191
        response = self.app.post(
192
            '/update', {
193
                "id" : str(correvent1_id) + "," + str(correvent2_id),
194
                "ack" : u'NoChange',
195
                "trouble_ticket" : u"foo",
196
                "last_modification": mktime(timestamp.timetuple()),
197
            }, status = 302, extra_environ = environ)
198

    
199
        response = response.follow(status=200, extra_environ = environ)
200
        assert_true(response.lxml.xpath(
201
            '//div[@id="flash"]/div[@class="error"]'))
202

    
203
        ### 3ème cas : L'utilisateur utilisé pour
204
        # se connecter à Vigiboard est 'access'.
205
        environ = {'REMOTE_USER': 'access'}
206

    
207
        # On s'attend à ce que le statut de la requête soit 302,
208
        # et à ce qu'un message informe l'utilisateur que les
209
        # évènements corrélés sélectionnées ont bien été mis à jour.
210
        response = self.app.post(
211
            '/update', {
212
                "id" : str(correvent1_id) + "," + str(correvent2_id),
213
                "last_modification": mktime(timestamp.timetuple()),
214
                "trouble_ticket" : u"foo",
215
                "ack" : u'NoChange',
216
            }, status = 302, extra_environ = environ)
217

    
218
        response = response.follow(status=200, extra_environ = environ)
219
        assert_false(response.lxml.xpath(
220
            '//div[@id="flash"]/div[@class="error"]'))
221
        assert_true(response.lxml.xpath(
222
            '//div[@id="flash"]/div[@class="ok"]'))
223

    
224
        # On s'assure que le ticket de l'évènement corrélé
225
        # a bien été mis à jour dans la base de données.
226
        correvents = DBSession.query(
227
            CorrEvent.trouble_ticket
228
            ).filter(CorrEvent.idcorrevent.in_([correvent1_id, correvent2_id])
229
            ).all()
230

    
231
        assert_equal(correvents[0].trouble_ticket, u"foo")
232
        assert_equal(correvents[1].trouble_ticket, u"foo")
233

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

    
237
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
238
        # et un groupe d'hôtes et de services associés à ces items.
239
        (hosts, services) = populate_DB()
240

    
241
        # On ajoute 2 évènements corrélés causés par ces hôtes
242
        timestamp = datetime.now()
243
        correvent1_id = add_correvent_caused_by(services[0], timestamp)
244
        correvent2_id = add_correvent_caused_by(services[1], timestamp)
245

    
246
        transaction.commit()
247

    
248
        ### 1er cas : L'utilisateur n'est pas connecté.
249
        # On vérifie que le plugin retourne bien une erreur 401.
250
        response = self.app.post(
251
            '/update', {
252
                "id" : str(correvent1_id) + "," + str(correvent2_id),
253
                "last_modification": mktime(timestamp.timetuple()),
254
                "trouble_ticket" : u"foo",
255
                "ack" : u'NoChange',
256
            }, status = 401)
257

    
258
        ### 2ème cas : L'utilisateur utilisé pour
259
        # se connecter à Vigiboard est 'limited_access'.
260
        environ = {'REMOTE_USER': 'limited_access'}
261

    
262
        # On s'attend à ce qu'une erreur 302 soit renvoyée, et à
263
        # ce qu'un message d'erreur précise à l'utilisateur qu'il
264
        # n'a pas la permission de modifier ces évènements.
265
        response = self.app.post(
266
            '/update', {
267
                "id" : str(correvent1_id) + "," + str(correvent2_id),
268
                "last_modification": mktime(timestamp.timetuple()),
269
                "trouble_ticket" : u"foo",
270
                "ack" : u'NoChange',
271
            }, status = 302, extra_environ = environ)
272

    
273
        response = response.follow(status=200, extra_environ = environ)
274
        assert_true(response.lxml.xpath(
275
            '//div[@id="flash"]/div[@class="error"]'))
276

    
277
        ### 3ème cas : L'utilisateur utilisé pour
278
        # se connecter à Vigiboard est 'access'.
279
        environ = {'REMOTE_USER': 'access'}
280

    
281
        # On s'attend à ce que le statut de la requête soit 302,
282
        # et à ce qu'un message informe l'utilisateur que les
283
        # évènements corrélés sélectionnées ont bien été mis à jour.
284
        response = self.app.post(
285
            '/update', {
286
                "id" : str(correvent1_id) + "," + str(correvent2_id),
287
                "last_modification": mktime(timestamp.timetuple()),
288
                "trouble_ticket" : u"foo",
289
                "ack" : u'NoChange',
290
            }, status = 302, extra_environ = environ)
291

    
292
        response = response.follow(status=200, extra_environ = environ)
293
        assert_false(response.lxml.xpath(
294
            '//div[@id="flash"]/div[@class="error"]'))
295
        assert_true(response.lxml.xpath(
296
            '//div[@id="flash"]/div[@class="ok"]'))
297

    
298
        # On s'assure que le ticket de l'évènement corrélé
299
        # a bien été mis à jour dans la base de données.
300
        correvents = DBSession.query(
301
            CorrEvent.trouble_ticket
302
            ).filter(CorrEvent.idcorrevent.in_([correvent1_id, correvent2_id])
303
            ).all()
304
        assert_equal(correvents[0].trouble_ticket, u"foo")
305
        assert_equal(correvents[1].trouble_ticket, u"foo")
306

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

    
310
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
311
        # et un groupe d'hôtes et de services associés à ces items.
312
        (hosts, services) = populate_DB()
313

    
314
        # On ajoute 2 évènements corrélés causés par ces hôtes
315
        timestamp = datetime.now()
316
        correvent1_id = add_correvent_caused_by(hosts[0], timestamp)
317
        correvent2_id = add_correvent_caused_by(hosts[1], timestamp)
318
        transaction.commit()
319

    
320
        ### 1er cas : L'utilisateur n'est pas connecté.
321
        # On vérifie que le plugin retourne bien une erreur 401.
322
        response = self.app.post(
323
            '/update', {
324
                "id" : str(correvent1_id) + "," + str(correvent2_id),
325
                "last_modification": mktime(timestamp.timetuple()),
326
                "trouble_ticket" : "",
327
                "ack" : u'Acknowledged',
328
            }, status = 401)
329

    
330
        ### 2ème cas : L'utilisateur utilisé pour
331
        # se connecter à Vigiboard est 'limited_access'.
332
        environ = {'REMOTE_USER': 'limited_access'}
333

    
334
        # On s'attend à ce qu'une erreur 302 soit renvoyée, et à
335
        # ce qu'un message d'erreur précise à l'utilisateur qu'il
336
        # n'a pas la permission de modifier ces évènements.
337
        response = self.app.post(
338
            '/update', {
339
                "id" : str(correvent1_id) + "," + str(correvent2_id),
340
                "last_modification": mktime(timestamp.timetuple()),
341
                "trouble_ticket" : "",
342
                "ack" : u'Acknowledged',
343
            }, status = 302, extra_environ = environ)
344

    
345
        response = response.follow(status=200, extra_environ = environ)
346
        assert_true(response.lxml.xpath(
347
            '//div[@id="flash"]/div[@class="error"]'))
348

    
349
        ### 3ème cas : L'utilisateur utilisé pour
350
        # se connecter à Vigiboard est 'access'.
351
        environ = {'REMOTE_USER': 'access'}
352

    
353
        # On s'attend à ce que le statut de la requête soit 302,
354
        # et à ce qu'un message informe l'utilisateur que les
355
        # évènements corrélés sélectionnées ont bien été mis à jour.
356
        response = self.app.post(
357
            '/update', {
358
                "id" : str(correvent1_id) + "," + str(correvent2_id),
359
                "last_modification": mktime(timestamp.timetuple()),
360
                "trouble_ticket" : "",
361
                "ack" : u'Acknowledged',
362
            }, status = 302, extra_environ = environ)
363

    
364
        response = response.follow(status=200, extra_environ = environ)
365
        assert_false(response.lxml.xpath(
366
            '//div[@id="flash"]/div[@class="error"]'))
367
        assert_true(response.lxml.xpath(
368
            '//div[@id="flash"]/div[@class="ok"]'))
369

    
370
        # On s'assure que le statut de l'évènement corrélé
371
        # a bien été mis à jour dans la base de données.
372
        correvents = DBSession.query(
373
            CorrEvent.status
374
            ).filter(CorrEvent.idcorrevent.in_([correvent1_id, correvent2_id])
375
            ).all()
376
        assert_equal(correvents[0].status, u'Acknowledged')
377
        assert_equal(correvents[1].status, u'Acknowledged')
378

    
379

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

    
383
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
384
        # et un groupe d'hôtes et de services associés à ces items.
385
        (hosts, services) = populate_DB()
386

    
387
        # On ajoute 2 évènements corrélés causés par ces hôtes
388
        timestamp = datetime.now()
389
        correvent1_id = add_correvent_caused_by(services[0], timestamp)
390
        correvent2_id = add_correvent_caused_by(services[1], timestamp)
391

    
392
        transaction.commit()
393

    
394
        ### 1er cas : L'utilisateur n'est pas connecté.
395
        # On vérifie que le plugin retourne bien une erreur 401.
396
        response = self.app.post(
397
            '/update', {
398
                "id" : str(correvent1_id) + "," + str(correvent2_id),
399
                "last_modification": mktime(timestamp.timetuple()),
400
                "trouble_ticket" : "",
401
                "ack" : u'Acknowledged',
402
            }, status = 401)
403

    
404
        ### 2ème cas : L'utilisateur utilisé pour
405
        # se connecter à Vigiboard est 'limited_access'.
406
        environ = {'REMOTE_USER': 'limited_access'}
407

    
408
        # On s'attend à ce qu'une erreur 302 soit renvoyée, et à
409
        # ce qu'un message d'erreur précise à l'utilisateur qu'il
410
        # n'a pas la permission de modifier ces évènements.
411
        response = self.app.post(
412
            '/update', {
413
                "id" : str(correvent1_id) + "," + str(correvent2_id),
414
                "last_modification": mktime(timestamp.timetuple()),
415
                "trouble_ticket" : "",
416
                "ack" : u'Acknowledged',
417
            }, status = 302, extra_environ = environ)
418

    
419
        response = response.follow(status=200, extra_environ = environ)
420
        assert_true(response.lxml.xpath(
421
            '//div[@id="flash"]/div[@class="error"]'))
422

    
423
        ### 3ème cas : L'utilisateur utilisé pour
424
        # se connecter à Vigiboard est 'access'.
425
        environ = {'REMOTE_USER': 'access'}
426

    
427
        # On s'attend à ce que le statut de la requête soit 302,
428
        # et à ce qu'un message informe l'utilisateur que les
429
        # évènements corrélés sélectionnées ont bien été mis à jour.
430
        response = self.app.post(
431
            '/update', {
432
                "id" : str(correvent1_id) + "," + str(correvent2_id),
433
                "last_modification": mktime(timestamp.timetuple()),
434
                "trouble_ticket" : "",
435
                "ack" : u'Acknowledged',
436
            }, status = 302, extra_environ = environ)
437

    
438
        response = response.follow(status=200, extra_environ = environ)
439
        assert_false(response.lxml.xpath(
440
            '//div[@id="flash"]/div[@class="error"]'))
441
        assert_true(response.lxml.xpath(
442
            '//div[@id="flash"]/div[@class="ok"]'))
443

    
444
        # On s'assure que le statut de l'évènement corrélé
445
        # a bien été mis à jour dans la base de données.
446
        correvents = DBSession.query(
447
            CorrEvent.status
448
            ).filter(CorrEvent.idcorrevent.in_([correvent1_id, correvent2_id])
449
            ).all()
450
        assert_equal(correvents[0].status, u'Acknowledged')
451
        assert_equal(correvents[1].status, u'Acknowledged')
452

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

    
456
        # On peuple la BDD avec 2 hôtes, 2 services de bas niveau,
457
        # et un groupe d'hôtes et de services associés à ces items.
458
        (hosts, services) = populate_DB()
459

    
460
        # On ajoute 2 évènements corrélés causés par ces hôtes
461
        timestamp = datetime.now()
462
        correvent1_id = add_correvent_caused_by(services[0], timestamp)
463
        correvent2_id = add_correvent_caused_by(services[1], timestamp)
464

    
465
        # Date de modification du premier évènement corrélé
466
        later_date = datetime.now()
467
        # Date du chargement de la page
468
        date = mktime(later_date.timetuple()) - 42
469

    
470
        # On ajoute une entrée dans l'historique de l'évènement brut
471
        # causant le premier évènement corrélé, portant pour timestamp
472
        # une date postérieure à celle du chargement de la page.
473
        correvent1 = DBSession.query(
474
            CorrEvent.idcause
475
            ).filter(CorrEvent.idcorrevent == correvent1_id).one()
476
        DBSession.add(EventHistory(
477
            type_action = u'Nagios update state',
478
            idevent = correvent1.idcause,
479
            timestamp = later_date))
480
        DBSession.flush()
481

    
482
        transaction.commit()
483

    
484
        # L'utilisateur utilisé pour se connecter à Vigiboard est 'access'.
485
        environ = {'REMOTE_USER': 'access'}
486

    
487
        # On s'attend à ce que le statut de la requête soit 302, et
488
        # à ce qu'un message d'erreur avise l'utilisateur que des
489
        # changements sont intervenus depuis le chargement de la page.
490
        response = self.app.post(
491
            '/update', {
492
                "id" : str(correvent1_id),
493
                "last_modification" : date,
494
                "trouble_ticket" : "",
495
                "ack" : u'Acknowledged',
496
            }, status = 302, extra_environ = environ)
497

    
498
        response = response.follow(status=200, extra_environ = environ)
499
        assert_true(response.lxml.xpath(
500
            '//div[@id="flash"]/div[@class="warning"]'))
501

    
502
        # On s'assure que le statut de l'évènement corrélé
503
        # n'a pas été modifié dans la base de données.
504
        status = DBSession.query(
505
            CorrEvent.status
506
            ).filter(CorrEvent.idcorrevent == correvent1_id
507
            ).scalar()
508
        assert_equal(status, u'None')