0002-tests-separate-statistics-API-tests-57663.patch
| tests/api/test_misc.py | ||
|---|---|---|
|
from django.utils.encoding import force_text
|
||
|
from django.utils.text import slugify
|
||
|
from requests.models import Response
|
||
|
from rest_framework import VERSION as drf_version
|
||
|
from authentic2.a2_rbac.models import Role
|
||
|
from authentic2.a2_rbac.utils import get_default_ou
|
||
|
from authentic2.apps.journal.models import Event, EventType
|
||
|
from authentic2.models import Attribute, AttributeValue, AuthorizedRole, Service
|
||
|
from authentic2.utils.misc import good_next_url
|
||
|
from django_rbac.models import SEARCH_OP
|
||
| ... | ... | |
|
assert_event('manager.user.deletion', user=admin, api=True)
|
||
|
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework')
|
||
|
def test_api_statistics_list(app, admin):
|
||
|
OU = get_ou_model()
|
||
|
headers = basic_authorization_header(admin)
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert len(resp.json['data']) == 6
|
||
|
login_stats = {
|
||
|
'name': 'Login count by authentication type',
|
||
|
'url': 'http://testserver/api/statistics/login/',
|
||
|
'id': 'login',
|
||
|
'filters': [
|
||
|
{
|
||
|
"id": "time_interval",
|
||
|
"label": "Time interval",
|
||
|
"options": [
|
||
|
{"id": "day", "label": "Day"},
|
||
|
{"id": "month", "label": "Month"},
|
||
|
{"id": "year", "label": "Year"},
|
||
|
],
|
||
|
"required": True,
|
||
|
"default": "month",
|
||
|
},
|
||
|
{'id': 'service', 'label': 'Service', 'options': []},
|
||
|
],
|
||
|
}
|
||
|
assert login_stats in resp.json['data']
|
||
|
assert {
|
||
|
'name': 'Login count by service',
|
||
|
'url': 'http://testserver/api/statistics/service_login/',
|
||
|
'id': 'service-login',
|
||
|
'filters': [
|
||
|
{
|
||
|
"id": "time_interval",
|
||
|
"label": "Time interval",
|
||
|
"options": [
|
||
|
{"id": "day", "label": "Day"},
|
||
|
{"id": "month", "label": "Month"},
|
||
|
{"id": "year", "label": "Year"},
|
||
|
],
|
||
|
"required": True,
|
||
|
"default": "month",
|
||
|
},
|
||
|
],
|
||
|
} in resp.json['data']
|
||
|
service = Service.objects.create(name='Service1', slug='service1', ou=get_default_ou())
|
||
|
service = Service.objects.create(name='Service2', slug='service2', ou=get_default_ou())
|
||
|
login_stats['filters'][1]['options'].append({'id': 'service1 default', 'label': 'Service1'})
|
||
|
login_stats['filters'][1]['options'].append({'id': 'service2 default', 'label': 'Service2'})
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert login_stats in resp.json['data']
|
||
|
# adding second ou doesn't change anything
|
||
|
ou = OU.objects.create(name='Second OU', slug='second')
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert login_stats in resp.json['data']
|
||
|
# if there are services in two differents OUs, filter is shown
|
||
|
service.ou = ou
|
||
|
service.save()
|
||
|
login_stats['filters'][1]['options'][1]['id'] = 'service2 second'
|
||
|
login_stats['filters'].append(
|
||
|
{
|
||
|
'id': 'services_ou',
|
||
|
'label': 'Services organizational unit',
|
||
|
'options': [
|
||
|
{'id': 'default', 'label': 'Default organizational unit'},
|
||
|
{'id': 'second', 'label': 'Second OU'},
|
||
|
],
|
||
|
}
|
||
|
)
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert login_stats in resp.json['data']
|
||
|
# same goes with users
|
||
|
User.objects.create(username='john.doe', email='john.doe@example.com', ou=ou)
|
||
|
login_stats['filters'].append(
|
||
|
{
|
||
|
'id': 'users_ou',
|
||
|
'label': 'Users organizational unit',
|
||
|
'options': [
|
||
|
{'id': 'default', 'label': 'Default organizational unit'},
|
||
|
{'id': 'second', 'label': 'Second OU'},
|
||
|
],
|
||
|
}
|
||
|
)
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert login_stats in resp.json['data']
|
||
|
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework')
|
||
|
@pytest.mark.parametrize(
|
||
|
'event_type_name,event_name', [('user.login', 'login'), ('user.registration', 'registration')]
|
||
|
)
|
||
|
def test_api_statistics(app, admin, freezer, event_type_name, event_name):
|
||
|
OU = get_ou_model()
|
||
|
headers = basic_authorization_header(admin)
|
||
|
resp = app.get('/api/statistics/login/?time_interval=month', headers=headers)
|
||
|
assert resp.json == {"data": {"series": [], "x_labels": []}, "err": 0}
|
||
|
user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou())
|
||
|
ou = OU.objects.create(name='Second OU', slug='second')
|
||
|
portal = Service.objects.create(name='portal', slug='portal', ou=ou)
|
||
|
agendas = Service.objects.create(name='agendas', slug='agendas', ou=get_default_ou())
|
||
|
method = {'how': 'password-on-https'}
|
||
|
method2 = {'how': 'fc'}
|
||
|
event_type = EventType.objects.get_for_name(event_type_name)
|
||
|
freezer.move_to('2020-02-03 12:00')
|
||
|
Event.objects.create(type=event_type, references=[portal], data=method)
|
||
|
Event.objects.create(type=event_type, references=[agendas, user], user=user, data=method)
|
||
|
freezer.move_to('2020-03-04 13:00')
|
||
|
Event.objects.create(type=event_type, references=[agendas], data=method)
|
||
|
Event.objects.create(type=event_type, references=[portal], data=method2)
|
||
|
resp = app.get('/api/statistics/%s/?time_interval=month' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02', '2020-03'],
|
||
|
'series': [{'label': 'FranceConnect', 'data': [None, 1]}, {'label': 'password', 'data': [2, 1]}],
|
||
|
}
|
||
|
# default time interval is 'month'
|
||
|
month_data = data
|
||
|
resp = app.get('/api/statistics/%s/' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert month_data == data
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&services_ou=default' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02', '2020-03'],
|
||
|
'series': [{'label': 'password', 'data': [1, 1]}],
|
||
|
}
|
||
|
# legacy way to filter by service OU
|
||
|
services_ou_data = data
|
||
|
resp = app.get('/api/statistics/%s/?time_interval=month&ou=default' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert services_ou_data == data
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&users_ou=default&service=agendas default' % event_name,
|
||
|
headers=headers,
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02'],
|
||
|
'series': [{'label': 'password', 'data': [1]}],
|
||
|
}
|
||
|
resp = app.get('/api/statistics/%s/?time_interval=month&users_ou=default' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [1]}]}
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&service=agendas default' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
assert data == {'x_labels': ['2020-02', '2020-03'], 'series': [{'label': 'password', 'data': [1, 1]}]}
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&start=2020-03-01T01:01' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-03'],
|
||
|
'series': [{'label': 'FranceConnect', 'data': [1]}, {'label': 'password', 'data': [1]}],
|
||
|
}
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&end=2020-03-01T01:01' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [2]}]}
|
||
|
resp = app.get('/api/statistics/%s/?time_interval=month&end=2020-03-01' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [2]}]}
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=year&service=portal second' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020'],
|
||
|
'series': [{'label': 'FranceConnect', 'data': [1]}, {'label': 'password', 'data': [1]}],
|
||
|
}
|
||
|
resp = app.get('/api/statistics/service_%s/?time_interval=month' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02', '2020-03'],
|
||
|
'series': [{'label': 'agendas', 'data': [1, 1]}, {'label': 'portal', 'data': [1, 1]}],
|
||
|
}
|
||
|
resp = app.get('/api/statistics/service_ou_%s/?time_interval=month' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02', '2020-03'],
|
||
|
'series': [
|
||
|
{'label': 'Default organizational unit', 'data': [1, 1]},
|
||
|
{'label': 'Second OU', 'data': [1, 1]},
|
||
|
],
|
||
|
}
|
||
|
def test_api_statistics_no_crash_older_drf(app, admin):
|
||
|
headers = basic_authorization_header(admin)
|
||
|
expected_status = 200 if drf_version > '3.9' else 404
|
||
|
app.get('/api/statistics/login/?time_interval=month', headers=headers, status=expected_status)
|
||
|
def test_find_duplicates_put(app, admin, settings):
|
||
|
app.authorization = ('Basic', (admin.username, admin.username))
|
||
|
app.put_json(
|
||
| tests/api/test_statistics.py | ||
|---|---|---|
|
# authentic2 - versatile identity manager
|
||
|
# Copyright (C) 2010-2019 Entr'ouvert
|
||
|
#
|
||
|
# This program is free software: you can redistribute it and/or modify it
|
||
|
# under the terms of the GNU Affero General Public License as published
|
||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||
|
# (at your option) any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU Affero General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU Affero General Public License
|
||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
import pytest
|
||
|
from rest_framework import VERSION as drf_version
|
||
|
from authentic2.a2_rbac.models import OrganizationalUnit as OU
|
||
|
from authentic2.a2_rbac.utils import get_default_ou
|
||
|
from authentic2.apps.journal.models import Event, EventType
|
||
|
from authentic2.custom_user.models import User
|
||
|
from authentic2.models import Service
|
||
|
from tests.utils import basic_authorization_header
|
||
|
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework')
|
||
|
def test_api_statistics_list(app, admin):
|
||
|
headers = basic_authorization_header(admin)
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert len(resp.json['data']) == 6
|
||
|
login_stats = {
|
||
|
'name': 'Login count by authentication type',
|
||
|
'url': 'http://testserver/api/statistics/login/',
|
||
|
'id': 'login',
|
||
|
'filters': [
|
||
|
{
|
||
|
"id": "time_interval",
|
||
|
"label": "Time interval",
|
||
|
"options": [
|
||
|
{"id": "day", "label": "Day"},
|
||
|
{"id": "month", "label": "Month"},
|
||
|
{"id": "year", "label": "Year"},
|
||
|
],
|
||
|
"required": True,
|
||
|
"default": "month",
|
||
|
},
|
||
|
{'id': 'service', 'label': 'Service', 'options': []},
|
||
|
],
|
||
|
}
|
||
|
assert login_stats in resp.json['data']
|
||
|
assert {
|
||
|
'name': 'Login count by service',
|
||
|
'url': 'http://testserver/api/statistics/service_login/',
|
||
|
'id': 'service-login',
|
||
|
'filters': [
|
||
|
{
|
||
|
"id": "time_interval",
|
||
|
"label": "Time interval",
|
||
|
"options": [
|
||
|
{"id": "day", "label": "Day"},
|
||
|
{"id": "month", "label": "Month"},
|
||
|
{"id": "year", "label": "Year"},
|
||
|
],
|
||
|
"required": True,
|
||
|
"default": "month",
|
||
|
},
|
||
|
],
|
||
|
} in resp.json['data']
|
||
|
service = Service.objects.create(name='Service1', slug='service1', ou=get_default_ou())
|
||
|
service = Service.objects.create(name='Service2', slug='service2', ou=get_default_ou())
|
||
|
login_stats['filters'][1]['options'].append({'id': 'service1 default', 'label': 'Service1'})
|
||
|
login_stats['filters'][1]['options'].append({'id': 'service2 default', 'label': 'Service2'})
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert login_stats in resp.json['data']
|
||
|
# adding second ou doesn't change anything
|
||
|
ou = OU.objects.create(name='Second OU', slug='second')
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert login_stats in resp.json['data']
|
||
|
# if there are services in two differents OUs, filter is shown
|
||
|
service.ou = ou
|
||
|
service.save()
|
||
|
login_stats['filters'][1]['options'][1]['id'] = 'service2 second'
|
||
|
login_stats['filters'].append(
|
||
|
{
|
||
|
'id': 'services_ou',
|
||
|
'label': 'Services organizational unit',
|
||
|
'options': [
|
||
|
{'id': 'default', 'label': 'Default organizational unit'},
|
||
|
{'id': 'second', 'label': 'Second OU'},
|
||
|
],
|
||
|
}
|
||
|
)
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert login_stats in resp.json['data']
|
||
|
# same goes with users
|
||
|
User.objects.create(username='john.doe', email='john.doe@example.com', ou=ou)
|
||
|
login_stats['filters'].append(
|
||
|
{
|
||
|
'id': 'users_ou',
|
||
|
'label': 'Users organizational unit',
|
||
|
'options': [
|
||
|
{'id': 'default', 'label': 'Default organizational unit'},
|
||
|
{'id': 'second', 'label': 'Second OU'},
|
||
|
],
|
||
|
}
|
||
|
)
|
||
|
resp = app.get('/api/statistics/', headers=headers)
|
||
|
assert login_stats in resp.json['data']
|
||
|
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework')
|
||
|
@pytest.mark.parametrize(
|
||
|
'event_type_name,event_name', [('user.login', 'login'), ('user.registration', 'registration')]
|
||
|
)
|
||
|
def test_api_statistics(app, admin, freezer, event_type_name, event_name):
|
||
|
headers = basic_authorization_header(admin)
|
||
|
resp = app.get('/api/statistics/login/?time_interval=month', headers=headers)
|
||
|
assert resp.json == {"data": {"series": [], "x_labels": []}, "err": 0}
|
||
|
user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou())
|
||
|
ou = OU.objects.create(name='Second OU', slug='second')
|
||
|
portal = Service.objects.create(name='portal', slug='portal', ou=ou)
|
||
|
agendas = Service.objects.create(name='agendas', slug='agendas', ou=get_default_ou())
|
||
|
method = {'how': 'password-on-https'}
|
||
|
method2 = {'how': 'fc'}
|
||
|
event_type = EventType.objects.get_for_name(event_type_name)
|
||
|
freezer.move_to('2020-02-03 12:00')
|
||
|
Event.objects.create(type=event_type, references=[portal], data=method)
|
||
|
Event.objects.create(type=event_type, references=[agendas, user], user=user, data=method)
|
||
|
freezer.move_to('2020-03-04 13:00')
|
||
|
Event.objects.create(type=event_type, references=[agendas], data=method)
|
||
|
Event.objects.create(type=event_type, references=[portal], data=method2)
|
||
|
resp = app.get('/api/statistics/%s/?time_interval=month' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02', '2020-03'],
|
||
|
'series': [{'label': 'FranceConnect', 'data': [None, 1]}, {'label': 'password', 'data': [2, 1]}],
|
||
|
}
|
||
|
# default time interval is 'month'
|
||
|
month_data = data
|
||
|
resp = app.get('/api/statistics/%s/' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert month_data == data
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&services_ou=default' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02', '2020-03'],
|
||
|
'series': [{'label': 'password', 'data': [1, 1]}],
|
||
|
}
|
||
|
# legacy way to filter by service OU
|
||
|
services_ou_data = data
|
||
|
resp = app.get('/api/statistics/%s/?time_interval=month&ou=default' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert services_ou_data == data
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&users_ou=default&service=agendas default' % event_name,
|
||
|
headers=headers,
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02'],
|
||
|
'series': [{'label': 'password', 'data': [1]}],
|
||
|
}
|
||
|
resp = app.get('/api/statistics/%s/?time_interval=month&users_ou=default' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [1]}]}
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&service=agendas default' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
assert data == {'x_labels': ['2020-02', '2020-03'], 'series': [{'label': 'password', 'data': [1, 1]}]}
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&start=2020-03-01T01:01' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-03'],
|
||
|
'series': [{'label': 'FranceConnect', 'data': [1]}, {'label': 'password', 'data': [1]}],
|
||
|
}
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=month&end=2020-03-01T01:01' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [2]}]}
|
||
|
resp = app.get('/api/statistics/%s/?time_interval=month&end=2020-03-01' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
assert data == {'x_labels': ['2020-02'], 'series': [{'label': 'password', 'data': [2]}]}
|
||
|
resp = app.get(
|
||
|
'/api/statistics/%s/?time_interval=year&service=portal second' % event_name, headers=headers
|
||
|
)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020'],
|
||
|
'series': [{'label': 'FranceConnect', 'data': [1]}, {'label': 'password', 'data': [1]}],
|
||
|
}
|
||
|
resp = app.get('/api/statistics/service_%s/?time_interval=month' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02', '2020-03'],
|
||
|
'series': [{'label': 'agendas', 'data': [1, 1]}, {'label': 'portal', 'data': [1, 1]}],
|
||
|
}
|
||
|
resp = app.get('/api/statistics/service_ou_%s/?time_interval=month' % event_name, headers=headers)
|
||
|
data = resp.json['data']
|
||
|
data['series'].sort(key=lambda x: x['label'])
|
||
|
assert data == {
|
||
|
'x_labels': ['2020-02', '2020-03'],
|
||
|
'series': [
|
||
|
{'label': 'Default organizational unit', 'data': [1, 1]},
|
||
|
{'label': 'Second OU', 'data': [1, 1]},
|
||
|
],
|
||
|
}
|
||
|
def test_api_statistics_no_crash_older_drf(app, admin):
|
||
|
headers = basic_authorization_header(admin)
|
||
|
expected_status = 200 if drf_version > '3.9' else 404
|
||
|
app.get('/api/statistics/login/?time_interval=month', headers=headers, status=expected_status)
|
||