Projet

Général

Profil

0002-tests-separate-statistics-API-tests-57663.patch

Benjamin Dauvergne, 06 octobre 2021 22:17

Télécharger (20,8 ko)

Voir les différences:

Subject: [PATCH 2/3] tests: separate statistics API tests (#57663)

 tests/api/test_misc.py       | 230 --------------------------------
 tests/api/test_statistics.py | 252 +++++++++++++++++++++++++++++++++++
 2 files changed, 252 insertions(+), 230 deletions(-)
 create mode 100644 tests/api/test_statistics.py
tests/api/test_misc.py
31 31
from django.utils.encoding import force_text
32 32
from django.utils.text import slugify
33 33
from requests.models import Response
34
from rest_framework import VERSION as drf_version
35 34

  
36 35
from authentic2.a2_rbac.models import Role
37 36
from authentic2.a2_rbac.utils import get_default_ou
38
from authentic2.apps.journal.models import Event, EventType
39 37
from authentic2.models import Attribute, AttributeValue, AuthorizedRole, Service
40 38
from authentic2.utils.misc import good_next_url
41 39
from django_rbac.models import SEARCH_OP
......
2307 2305
    assert_event('manager.user.deletion', user=admin, api=True)
2308 2306

  
2309 2307

  
2310
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework')
2311
def test_api_statistics_list(app, admin):
2312
    OU = get_ou_model()
2313
    headers = basic_authorization_header(admin)
2314
    resp = app.get('/api/statistics/', headers=headers)
2315
    assert len(resp.json['data']) == 6
2316
    login_stats = {
2317
        'name': 'Login count by authentication type',
2318
        'url': 'http://testserver/api/statistics/login/',
2319
        'id': 'login',
2320
        'filters': [
2321
            {
2322
                "id": "time_interval",
2323
                "label": "Time interval",
2324
                "options": [
2325
                    {"id": "day", "label": "Day"},
2326
                    {"id": "month", "label": "Month"},
2327
                    {"id": "year", "label": "Year"},
2328
                ],
2329
                "required": True,
2330
                "default": "month",
2331
            },
2332
            {'id': 'service', 'label': 'Service', 'options': []},
2333
        ],
2334
    }
2335
    assert login_stats in resp.json['data']
2336
    assert {
2337
        'name': 'Login count by service',
2338
        'url': 'http://testserver/api/statistics/service_login/',
2339
        'id': 'service-login',
2340
        'filters': [
2341
            {
2342
                "id": "time_interval",
2343
                "label": "Time interval",
2344
                "options": [
2345
                    {"id": "day", "label": "Day"},
2346
                    {"id": "month", "label": "Month"},
2347
                    {"id": "year", "label": "Year"},
2348
                ],
2349
                "required": True,
2350
                "default": "month",
2351
            },
2352
        ],
2353
    } in resp.json['data']
2354

  
2355
    service = Service.objects.create(name='Service1', slug='service1', ou=get_default_ou())
2356
    service = Service.objects.create(name='Service2', slug='service2', ou=get_default_ou())
2357
    login_stats['filters'][1]['options'].append({'id': 'service1 default', 'label': 'Service1'})
2358
    login_stats['filters'][1]['options'].append({'id': 'service2 default', 'label': 'Service2'})
2359

  
2360
    resp = app.get('/api/statistics/', headers=headers)
2361
    assert login_stats in resp.json['data']
2362

  
2363
    # adding second ou doesn't change anything
2364
    ou = OU.objects.create(name='Second OU', slug='second')
2365
    resp = app.get('/api/statistics/', headers=headers)
2366
    assert login_stats in resp.json['data']
2367

  
2368
    # if there are services in two differents OUs, filter is shown
2369
    service.ou = ou
2370
    service.save()
2371
    login_stats['filters'][1]['options'][1]['id'] = 'service2 second'
2372
    login_stats['filters'].append(
2373
        {
2374
            'id': 'services_ou',
2375
            'label': 'Services organizational unit',
2376
            'options': [
2377
                {'id': 'default', 'label': 'Default organizational unit'},
2378
                {'id': 'second', 'label': 'Second OU'},
2379
            ],
2380
        }
2381
    )
2382
    resp = app.get('/api/statistics/', headers=headers)
2383
    assert login_stats in resp.json['data']
2384

  
2385
    # same goes with users
2386
    User.objects.create(username='john.doe', email='john.doe@example.com', ou=ou)
2387
    login_stats['filters'].append(
2388
        {
2389
            'id': 'users_ou',
2390
            'label': 'Users organizational unit',
2391
            'options': [
2392
                {'id': 'default', 'label': 'Default organizational unit'},
2393
                {'id': 'second', 'label': 'Second OU'},
2394
            ],
2395
        }
2396
    )
2397
    resp = app.get('/api/statistics/', headers=headers)
2398
    assert login_stats in resp.json['data']
2399

  
2400

  
2401
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework')
2402
@pytest.mark.parametrize(
2403
    'event_type_name,event_name', [('user.login', 'login'), ('user.registration', 'registration')]
2404
)
2405
def test_api_statistics(app, admin, freezer, event_type_name, event_name):
2406
    OU = get_ou_model()
2407
    headers = basic_authorization_header(admin)
2408

  
2409
    resp = app.get('/api/statistics/login/?time_interval=month', headers=headers)
2410
    assert resp.json == {"data": {"series": [], "x_labels": []}, "err": 0}
2411

  
2412
    user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou())
2413
    ou = OU.objects.create(name='Second OU', slug='second')
2414
    portal = Service.objects.create(name='portal', slug='portal', ou=ou)
2415
    agendas = Service.objects.create(name='agendas', slug='agendas', ou=get_default_ou())
2416

  
2417
    method = {'how': 'password-on-https'}
2418
    method2 = {'how': 'fc'}
2419

  
2420
    event_type = EventType.objects.get_for_name(event_type_name)
2421

  
2422
    freezer.move_to('2020-02-03 12:00')
2423
    Event.objects.create(type=event_type, references=[portal], data=method)
2424
    Event.objects.create(type=event_type, references=[agendas, user], user=user, data=method)
2425

  
2426
    freezer.move_to('2020-03-04 13:00')
2427
    Event.objects.create(type=event_type, references=[agendas], data=method)
2428
    Event.objects.create(type=event_type, references=[portal], data=method2)
2429

  
2430
    resp = app.get('/api/statistics/%s/?time_interval=month' % event_name, headers=headers)
2431
    data = resp.json['data']
2432
    data['series'].sort(key=lambda x: x['label'])
2433
    assert data == {
2434
        'x_labels': ['2020-02', '2020-03'],
2435
        'series': [{'label': 'FranceConnect', 'data': [None, 1]}, {'label': 'password', 'data': [2, 1]}],
2436
    }
2437

  
2438
    # default time interval is 'month'
2439
    month_data = data
2440
    resp = app.get('/api/statistics/%s/' % event_name, headers=headers)
2441
    data = resp.json['data']
2442
    data['series'].sort(key=lambda x: x['label'])
2443
    assert month_data == data
2444

  
2445
    resp = app.get(
2446
        '/api/statistics/%s/?time_interval=month&services_ou=default' % event_name, headers=headers
2447
    )
2448
    data = resp.json['data']
2449
    data['series'].sort(key=lambda x: x['label'])
2450
    assert data == {
2451
        'x_labels': ['2020-02', '2020-03'],
2452
        'series': [{'label': 'password', 'data': [1, 1]}],
2453
    }
2454

  
2455
    # legacy way to filter by service OU
2456
    services_ou_data = data
2457
    resp = app.get('/api/statistics/%s/?time_interval=month&ou=default' % event_name, headers=headers)
2458
    data = resp.json['data']
2459
    data['series'].sort(key=lambda x: x['label'])
2460
    assert services_ou_data == data
2461

  
2462
    resp = app.get(
2463
        '/api/statistics/%s/?time_interval=month&users_ou=default&service=agendas default' % event_name,
2464
        headers=headers,
2465
    )
2466
    data = resp.json['data']
2467
    assert data == {
2468
        'x_labels': ['2020-02'],
2469
        'series': [{'label': 'password', 'data': [1]}],
2470
    }
2471

  
2472
    resp = app.get('/api/statistics/%s/?time_interval=month&users_ou=default' % event_name, headers=headers)
2473
    data = resp.json['data']
2474
    assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [1]}]}
2475

  
2476
    resp = app.get(
2477
        '/api/statistics/%s/?time_interval=month&service=agendas default' % event_name, headers=headers
2478
    )
2479
    data = resp.json['data']
2480
    assert data == {'x_labels': ['2020-02', '2020-03'], 'series': [{'label': 'password', 'data': [1, 1]}]}
2481

  
2482
    resp = app.get(
2483
        '/api/statistics/%s/?time_interval=month&start=2020-03-01T01:01' % event_name, headers=headers
2484
    )
2485
    data = resp.json['data']
2486
    data['series'].sort(key=lambda x: x['label'])
2487
    assert data == {
2488
        'x_labels': ['2020-03'],
2489
        'series': [{'label': 'FranceConnect', 'data': [1]}, {'label': 'password', 'data': [1]}],
2490
    }
2491

  
2492
    resp = app.get(
2493
        '/api/statistics/%s/?time_interval=month&end=2020-03-01T01:01' % event_name, headers=headers
2494
    )
2495
    data = resp.json['data']
2496
    assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [2]}]}
2497

  
2498
    resp = app.get('/api/statistics/%s/?time_interval=month&end=2020-03-01' % event_name, headers=headers)
2499
    data = resp.json['data']
2500
    assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [2]}]}
2501

  
2502
    resp = app.get(
2503
        '/api/statistics/%s/?time_interval=year&service=portal second' % event_name, headers=headers
2504
    )
2505
    data = resp.json['data']
2506
    data['series'].sort(key=lambda x: x['label'])
2507
    assert data == {
2508
        'x_labels': ['2020'],
2509
        'series': [{'label': 'FranceConnect', 'data': [1]}, {'label': 'password', 'data': [1]}],
2510
    }
2511

  
2512
    resp = app.get('/api/statistics/service_%s/?time_interval=month' % event_name, headers=headers)
2513
    data = resp.json['data']
2514
    data['series'].sort(key=lambda x: x['label'])
2515
    assert data == {
2516
        'x_labels': ['2020-02', '2020-03'],
2517
        'series': [{'label': 'agendas', 'data': [1, 1]}, {'label': 'portal', 'data': [1, 1]}],
2518
    }
2519

  
2520
    resp = app.get('/api/statistics/service_ou_%s/?time_interval=month' % event_name, headers=headers)
2521
    data = resp.json['data']
2522
    data['series'].sort(key=lambda x: x['label'])
2523
    assert data == {
2524
        'x_labels': ['2020-02', '2020-03'],
2525
        'series': [
2526
            {'label': 'Default organizational unit', 'data': [1, 1]},
2527
            {'label': 'Second OU', 'data': [1, 1]},
2528
        ],
2529
    }
2530

  
2531

  
2532
def test_api_statistics_no_crash_older_drf(app, admin):
2533
    headers = basic_authorization_header(admin)
2534
    expected_status = 200 if drf_version > '3.9' else 404
2535
    app.get('/api/statistics/login/?time_interval=month', headers=headers, status=expected_status)
2536

  
2537

  
2538 2308
def test_find_duplicates_put(app, admin, settings):
2539 2309
    app.authorization = ('Basic', (admin.username, admin.username))
2540 2310
    app.put_json(
tests/api/test_statistics.py
1
# authentic2 - versatile identity manager
2
# Copyright (C) 2010-2019 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17

  
18
import pytest
19
from rest_framework import VERSION as drf_version
20

  
21
from authentic2.a2_rbac.models import OrganizationalUnit as OU
22
from authentic2.a2_rbac.utils import get_default_ou
23
from authentic2.apps.journal.models import Event, EventType
24
from authentic2.custom_user.models import User
25
from authentic2.models import Service
26
from tests.utils import basic_authorization_header
27

  
28

  
29
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework')
30
def test_api_statistics_list(app, admin):
31
    headers = basic_authorization_header(admin)
32
    resp = app.get('/api/statistics/', headers=headers)
33
    assert len(resp.json['data']) == 6
34
    login_stats = {
35
        'name': 'Login count by authentication type',
36
        'url': 'http://testserver/api/statistics/login/',
37
        'id': 'login',
38
        'filters': [
39
            {
40
                "id": "time_interval",
41
                "label": "Time interval",
42
                "options": [
43
                    {"id": "day", "label": "Day"},
44
                    {"id": "month", "label": "Month"},
45
                    {"id": "year", "label": "Year"},
46
                ],
47
                "required": True,
48
                "default": "month",
49
            },
50
            {'id': 'service', 'label': 'Service', 'options': []},
51
        ],
52
    }
53
    assert login_stats in resp.json['data']
54
    assert {
55
        'name': 'Login count by service',
56
        'url': 'http://testserver/api/statistics/service_login/',
57
        'id': 'service-login',
58
        'filters': [
59
            {
60
                "id": "time_interval",
61
                "label": "Time interval",
62
                "options": [
63
                    {"id": "day", "label": "Day"},
64
                    {"id": "month", "label": "Month"},
65
                    {"id": "year", "label": "Year"},
66
                ],
67
                "required": True,
68
                "default": "month",
69
            },
70
        ],
71
    } in resp.json['data']
72

  
73
    service = Service.objects.create(name='Service1', slug='service1', ou=get_default_ou())
74
    service = Service.objects.create(name='Service2', slug='service2', ou=get_default_ou())
75
    login_stats['filters'][1]['options'].append({'id': 'service1 default', 'label': 'Service1'})
76
    login_stats['filters'][1]['options'].append({'id': 'service2 default', 'label': 'Service2'})
77

  
78
    resp = app.get('/api/statistics/', headers=headers)
79
    assert login_stats in resp.json['data']
80

  
81
    # adding second ou doesn't change anything
82
    ou = OU.objects.create(name='Second OU', slug='second')
83
    resp = app.get('/api/statistics/', headers=headers)
84
    assert login_stats in resp.json['data']
85

  
86
    # if there are services in two differents OUs, filter is shown
87
    service.ou = ou
88
    service.save()
89
    login_stats['filters'][1]['options'][1]['id'] = 'service2 second'
90
    login_stats['filters'].append(
91
        {
92
            'id': 'services_ou',
93
            'label': 'Services organizational unit',
94
            'options': [
95
                {'id': 'default', 'label': 'Default organizational unit'},
96
                {'id': 'second', 'label': 'Second OU'},
97
            ],
98
        }
99
    )
100
    resp = app.get('/api/statistics/', headers=headers)
101
    assert login_stats in resp.json['data']
102

  
103
    # same goes with users
104
    User.objects.create(username='john.doe', email='john.doe@example.com', ou=ou)
105
    login_stats['filters'].append(
106
        {
107
            'id': 'users_ou',
108
            'label': 'Users organizational unit',
109
            'options': [
110
                {'id': 'default', 'label': 'Default organizational unit'},
111
                {'id': 'second', 'label': 'Second OU'},
112
            ],
113
        }
114
    )
115
    resp = app.get('/api/statistics/', headers=headers)
116
    assert login_stats in resp.json['data']
117

  
118

  
119
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework')
120
@pytest.mark.parametrize(
121
    'event_type_name,event_name', [('user.login', 'login'), ('user.registration', 'registration')]
122
)
123
def test_api_statistics(app, admin, freezer, event_type_name, event_name):
124
    headers = basic_authorization_header(admin)
125

  
126
    resp = app.get('/api/statistics/login/?time_interval=month', headers=headers)
127
    assert resp.json == {"data": {"series": [], "x_labels": []}, "err": 0}
128

  
129
    user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou())
130
    ou = OU.objects.create(name='Second OU', slug='second')
131
    portal = Service.objects.create(name='portal', slug='portal', ou=ou)
132
    agendas = Service.objects.create(name='agendas', slug='agendas', ou=get_default_ou())
133

  
134
    method = {'how': 'password-on-https'}
135
    method2 = {'how': 'fc'}
136

  
137
    event_type = EventType.objects.get_for_name(event_type_name)
138

  
139
    freezer.move_to('2020-02-03 12:00')
140
    Event.objects.create(type=event_type, references=[portal], data=method)
141
    Event.objects.create(type=event_type, references=[agendas, user], user=user, data=method)
142

  
143
    freezer.move_to('2020-03-04 13:00')
144
    Event.objects.create(type=event_type, references=[agendas], data=method)
145
    Event.objects.create(type=event_type, references=[portal], data=method2)
146

  
147
    resp = app.get('/api/statistics/%s/?time_interval=month' % event_name, headers=headers)
148
    data = resp.json['data']
149
    data['series'].sort(key=lambda x: x['label'])
150
    assert data == {
151
        'x_labels': ['2020-02', '2020-03'],
152
        'series': [{'label': 'FranceConnect', 'data': [None, 1]}, {'label': 'password', 'data': [2, 1]}],
153
    }
154

  
155
    # default time interval is 'month'
156
    month_data = data
157
    resp = app.get('/api/statistics/%s/' % event_name, headers=headers)
158
    data = resp.json['data']
159
    data['series'].sort(key=lambda x: x['label'])
160
    assert month_data == data
161

  
162
    resp = app.get(
163
        '/api/statistics/%s/?time_interval=month&services_ou=default' % event_name, headers=headers
164
    )
165
    data = resp.json['data']
166
    data['series'].sort(key=lambda x: x['label'])
167
    assert data == {
168
        'x_labels': ['2020-02', '2020-03'],
169
        'series': [{'label': 'password', 'data': [1, 1]}],
170
    }
171

  
172
    # legacy way to filter by service OU
173
    services_ou_data = data
174
    resp = app.get('/api/statistics/%s/?time_interval=month&ou=default' % event_name, headers=headers)
175
    data = resp.json['data']
176
    data['series'].sort(key=lambda x: x['label'])
177
    assert services_ou_data == data
178

  
179
    resp = app.get(
180
        '/api/statistics/%s/?time_interval=month&users_ou=default&service=agendas default' % event_name,
181
        headers=headers,
182
    )
183
    data = resp.json['data']
184
    assert data == {
185
        'x_labels': ['2020-02'],
186
        'series': [{'label': 'password', 'data': [1]}],
187
    }
188

  
189
    resp = app.get('/api/statistics/%s/?time_interval=month&users_ou=default' % event_name, headers=headers)
190
    data = resp.json['data']
191
    assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [1]}]}
192

  
193
    resp = app.get(
194
        '/api/statistics/%s/?time_interval=month&service=agendas default' % event_name, headers=headers
195
    )
196
    data = resp.json['data']
197
    assert data == {'x_labels': ['2020-02', '2020-03'], 'series': [{'label': 'password', 'data': [1, 1]}]}
198

  
199
    resp = app.get(
200
        '/api/statistics/%s/?time_interval=month&start=2020-03-01T01:01' % event_name, headers=headers
201
    )
202
    data = resp.json['data']
203
    data['series'].sort(key=lambda x: x['label'])
204
    assert data == {
205
        'x_labels': ['2020-03'],
206
        'series': [{'label': 'FranceConnect', 'data': [1]}, {'label': 'password', 'data': [1]}],
207
    }
208

  
209
    resp = app.get(
210
        '/api/statistics/%s/?time_interval=month&end=2020-03-01T01:01' % event_name, headers=headers
211
    )
212
    data = resp.json['data']
213
    assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [2]}]}
214

  
215
    resp = app.get('/api/statistics/%s/?time_interval=month&end=2020-03-01' % event_name, headers=headers)
216
    data = resp.json['data']
217
    assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [2]}]}
218

  
219
    resp = app.get(
220
        '/api/statistics/%s/?time_interval=year&service=portal second' % event_name, headers=headers
221
    )
222
    data = resp.json['data']
223
    data['series'].sort(key=lambda x: x['label'])
224
    assert data == {
225
        'x_labels': ['2020'],
226
        'series': [{'label': 'FranceConnect', 'data': [1]}, {'label': 'password', 'data': [1]}],
227
    }
228

  
229
    resp = app.get('/api/statistics/service_%s/?time_interval=month' % event_name, headers=headers)
230
    data = resp.json['data']
231
    data['series'].sort(key=lambda x: x['label'])
232
    assert data == {
233
        'x_labels': ['2020-02', '2020-03'],
234
        'series': [{'label': 'agendas', 'data': [1, 1]}, {'label': 'portal', 'data': [1, 1]}],
235
    }
236

  
237
    resp = app.get('/api/statistics/service_ou_%s/?time_interval=month' % event_name, headers=headers)
238
    data = resp.json['data']
239
    data['series'].sort(key=lambda x: x['label'])
240
    assert data == {
241
        'x_labels': ['2020-02', '2020-03'],
242
        'series': [
243
            {'label': 'Default organizational unit', 'data': [1, 1]},
244
            {'label': 'Second OU', 'data': [1, 1]},
245
        ],
246
    }
247

  
248

  
249
def test_api_statistics_no_crash_older_drf(app, admin):
250
    headers = basic_authorization_header(admin)
251
    expected_status = 200 if drf_version > '3.9' else 404
252
    app.get('/api/statistics/login/?time_interval=month', headers=headers, status=expected_status)
0
-