mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-27 07:02:26 +00:00
771 lines
31 KiB
Python
771 lines
31 KiB
Python
# -*- mode: python; coding: utf-8 -*-
|
|
# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il
|
|
# se veut agnostique au réseau considéré, de manière à être installable en
|
|
# quelques clics.
|
|
#
|
|
# Copyright © 2018 Maël Kervella
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 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 General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
"""Defines the test suite for the API
|
|
"""
|
|
|
|
import datetime
|
|
import json
|
|
|
|
from requests import codes
|
|
from rest_framework.test import APITestCase
|
|
|
|
import cotisations.models as cotisations
|
|
import machines.models as machines
|
|
import preferences.models as preferences
|
|
import topologie.models as topologie
|
|
import users.models as users
|
|
|
|
|
|
class APIEndpointsTestCase(APITestCase):
|
|
"""Test case to test that all endpoints are reachable with respects to
|
|
authentication and permission checks.
|
|
|
|
Attributes:
|
|
no_auth_endpoints: A list of endpoints that should be reachable
|
|
without authentication.
|
|
auth_no_perm_endpoints: A list of endpoints that should be reachable
|
|
when being authenticated but without permissions.
|
|
auth_perm_endpoints: A list of endpoints that should be reachable
|
|
when being authenticated and having the correct permissions.
|
|
stduser: A standard user with no permission used for the tests and
|
|
initialized at the beggining of this test case.
|
|
superuser: A superuser (with all permissions) used for the tests and
|
|
initialized at the beggining of this test case.
|
|
"""
|
|
|
|
no_auth_endpoints = ["/api/"]
|
|
auth_no_perm_endpoints = []
|
|
auth_perm_endpoints = [
|
|
"/api/cotisations/article/",
|
|
"/api/cotisations/article/1/",
|
|
"/api/cotisations/banque/",
|
|
"/api/cotisations/banque/1/",
|
|
"/api/cotisations/cotisation/",
|
|
"/api/cotisations/cotisation/1/",
|
|
"/api/cotisations/facture/",
|
|
"/api/cotisations/facture/1/",
|
|
"/api/cotisations/paiement/",
|
|
"/api/cotisations/paiement/1/",
|
|
"/api/cotisations/vente/",
|
|
"/api/cotisations/vente/1/",
|
|
"/api/machines/domain/",
|
|
"/api/machines/domain/1/",
|
|
"/api/machines/extension/",
|
|
"/api/machines/extension/1/",
|
|
"/api/machines/interface/",
|
|
"/api/machines/interface/1/",
|
|
"/api/machines/iplist/",
|
|
"/api/machines/iplist/1/",
|
|
"/api/machines/iptype/",
|
|
"/api/machines/iptype/1/",
|
|
"/api/machines/ipv6list/",
|
|
"/api/machines/ipv6list/1/",
|
|
"/api/machines/machine/",
|
|
"/api/machines/machine/1/",
|
|
"/api/machines/machinetype/",
|
|
"/api/machines/machinetype/1/",
|
|
"/api/machines/mx/",
|
|
"/api/machines/mx/1/",
|
|
"/api/machines/nas/",
|
|
"/api/machines/nas/1/",
|
|
"/api/machines/ns/",
|
|
"/api/machines/ns/1/",
|
|
"/api/machines/ouvertureportlist/",
|
|
"/api/machines/ouvertureportlist/1/",
|
|
"/api/machines/ouvertureport/",
|
|
"/api/machines/ouvertureport/1/",
|
|
"/api/machines/servicelink/",
|
|
"/api/machines/servicelink/1/",
|
|
"/api/machines/service/",
|
|
"/api/machines/service/1/",
|
|
"/api/machines/soa/",
|
|
"/api/machines/soa/1/",
|
|
"/api/machines/srv/",
|
|
"/api/machines/srv/1/",
|
|
"/api/machines/txt/",
|
|
"/api/machines/txt/1/",
|
|
"/api/machines/vlan/",
|
|
"/api/machines/vlan/1/",
|
|
"/api/preferences/optionaluser/",
|
|
"/api/preferences/optionalmachine/",
|
|
"/api/preferences/optionaltopologie/",
|
|
"/api/preferences/generaloption/",
|
|
"/api/preferences/service/",
|
|
"/api/preferences/service/1/",
|
|
"/api/preferences/assooption/",
|
|
"/api/preferences/homeoption/",
|
|
"/api/preferences/mailmessageoption/",
|
|
"/api/topologie/acesspoint/",
|
|
# 2nd machine to be create (machines_machine_1, topologie_accesspoint_1)
|
|
"/api/topologie/acesspoint/2/",
|
|
"/api/topologie/building/",
|
|
"/api/topologie/building/1/",
|
|
"/api/topologie/constructorswitch/",
|
|
"/api/topologie/constructorswitch/1/",
|
|
"/api/topologie/modelswitch/",
|
|
"/api/topologie/modelswitch/1/",
|
|
"/api/topologie/room/",
|
|
"/api/topologie/room/1/",
|
|
"/api/topologie/server/",
|
|
# 3rd machine to be create (machines_machine_1, topologie_accesspoint_1,
|
|
# topologie_server_1)
|
|
"/api/topologie/server/3/",
|
|
"/api/topologie/stack/",
|
|
"/api/topologie/stack/1/",
|
|
"/api/topologie/switch/",
|
|
# 4th machine to be create (machines_machine_1, topologie_accesspoint_1,
|
|
# topologie_server_1, topologie_switch_1)
|
|
"/api/topologie/switch/4/",
|
|
"/api/topologie/switchbay/",
|
|
"/api/topologie/switchbay/1/",
|
|
"/api/topologie/switchport/",
|
|
"/api/topologie/switchport/1/",
|
|
"/api/topologie/switchport/2/",
|
|
"/api/topologie/switchport/3/",
|
|
"/api/users/adherent/",
|
|
# 3rd user to be create (stduser, superuser, users_adherent_1)
|
|
"/api/users/adherent/3/",
|
|
"/api/users/ban/",
|
|
"/api/users/ban/1/",
|
|
"/api/users/club/",
|
|
# 4th user to be create (stduser, superuser, users_adherent_1,
|
|
# users_club_1)
|
|
"/api/users/club/4/",
|
|
"/api/users/listright/",
|
|
# TODO: Merge !145
|
|
# '/api/users/listright/1/',
|
|
"/api/users/school/",
|
|
"/api/users/school/1/",
|
|
"/api/users/serviceuser/",
|
|
"/api/users/serviceuser/1/",
|
|
"/api/users/shell/",
|
|
"/api/users/shell/1/",
|
|
"/api/users/user/",
|
|
"/api/users/user/1/",
|
|
"/api/users/whitelist/",
|
|
"/api/users/whitelist/1/",
|
|
"/api/dns/zones/",
|
|
"/api/dhcp/hostmacip/",
|
|
"/api/mailing/standard",
|
|
"/api/mailing/club",
|
|
"/api/services/regen/",
|
|
]
|
|
not_found_endpoints = [
|
|
"/api/cotisations/article/4242/",
|
|
"/api/cotisations/banque/4242/",
|
|
"/api/cotisations/cotisation/4242/",
|
|
"/api/cotisations/facture/4242/",
|
|
"/api/cotisations/paiement/4242/",
|
|
"/api/cotisations/vente/4242/",
|
|
"/api/machines/domain/4242/",
|
|
"/api/machines/extension/4242/",
|
|
"/api/machines/interface/4242/",
|
|
"/api/machines/iplist/4242/",
|
|
"/api/machines/iptype/4242/",
|
|
"/api/machines/ipv6list/4242/",
|
|
"/api/machines/machine/4242/",
|
|
"/api/machines/machinetype/4242/",
|
|
"/api/machines/mx/4242/",
|
|
"/api/machines/nas/4242/",
|
|
"/api/machines/ns/4242/",
|
|
"/api/machines/ouvertureportlist/4242/",
|
|
"/api/machines/ouvertureport/4242/",
|
|
"/api/machines/servicelink/4242/",
|
|
"/api/machines/service/4242/",
|
|
"/api/machines/soa/4242/",
|
|
"/api/machines/srv/4242/",
|
|
"/api/machines/txt/4242/",
|
|
"/api/machines/vlan/4242/",
|
|
"/api/preferences/service/4242/",
|
|
"/api/topologie/acesspoint/4242/",
|
|
"/api/topologie/building/4242/",
|
|
"/api/topologie/constructorswitch/4242/",
|
|
"/api/topologie/modelswitch/4242/",
|
|
"/api/topologie/room/4242/",
|
|
"/api/topologie/server/4242/",
|
|
"/api/topologie/stack/4242/",
|
|
"/api/topologie/switch/4242/",
|
|
"/api/topologie/switchbay/4242/",
|
|
"/api/topologie/switchport/4242/",
|
|
"/api/users/adherent/4242/",
|
|
"/api/users/ban/4242/",
|
|
"/api/users/club/4242/",
|
|
"/api/users/listright/4242/",
|
|
"/api/users/school/4242/",
|
|
"/api/users/serviceuser/4242/",
|
|
"/api/users/shell/4242/",
|
|
"/api/users/user/4242/",
|
|
"/api/users/whitelist/4242/",
|
|
]
|
|
|
|
stduser = None
|
|
superuser = None
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
# Be aware that every object created here is never actually committed
|
|
# to the database. TestCase uses rollbacks after each test to cancel all
|
|
# modifications and recreates the data defined here before each test.
|
|
# For more details, see
|
|
# https://docs.djangoproject.com/en/1.10/topics/testing/tools/#testcase
|
|
|
|
super(APIEndpointsTestCase, cls).setUpClass()
|
|
|
|
# A user with no rights
|
|
cls.stduser = users.User.objects.create_user(
|
|
"apistduser", "apistduser", "apistduser@example.net", "apistduser"
|
|
)
|
|
# A user with all the rights
|
|
cls.superuser = users.User.objects.create_superuser(
|
|
"apisuperuser", "apisuperuser", "apisuperuser@example.net", "apisuperuser"
|
|
)
|
|
|
|
# Creates 1 instance for each object so the "details" endpoints
|
|
# can be tested too. Objects need to be created in the right order.
|
|
# Dependencies (relatedFields, ...) are highlighted by a comment at
|
|
# the end of the concerned line (# Dep <model>).
|
|
cls.users_school_1 = users.School.objects.create(name="users_school_1")
|
|
cls.users_school_1.save()
|
|
cls.users_listshell_1 = users.ListShell.objects.create(
|
|
shell="users_listshell_1"
|
|
)
|
|
cls.users_adherent_1 = users.Adherent.objects.create(
|
|
password="password",
|
|
last_login=datetime.datetime.now(datetime.timezone.utc),
|
|
surname="users_adherent_1",
|
|
pseudo="usersadherent1",
|
|
email="users_adherent_1@example.net",
|
|
school=cls.users_school_1, # Dep users.School
|
|
shell=cls.users_listshell_1, # Dep users.ListShell
|
|
comment="users Adherent 1 comment",
|
|
pwd_ntlm="",
|
|
state=users.User.STATES[0][0],
|
|
registered=datetime.datetime.now(datetime.timezone.utc),
|
|
telephone="0123456789",
|
|
uid_number=21102,
|
|
rezo_rez_uid=21102,
|
|
)
|
|
cls.users_user_1 = cls.users_adherent_1
|
|
cls.cotisations_article_1 = cotisations.Article.objects.create(
|
|
name="cotisations_article_1",
|
|
prix=10,
|
|
duration=1,
|
|
type_user=cotisations.Article.USER_TYPES[0][0],
|
|
type_cotisation=cotisations.Article.COTISATION_TYPE[0][0],
|
|
)
|
|
cls.cotisations_banque_1 = cotisations.Banque.objects.create(
|
|
name="cotisations_banque_1"
|
|
)
|
|
cls.cotisations_paiement_1 = cotisations.Paiement.objects.create(
|
|
moyen="cotisations_paiement_1",
|
|
type_paiement=cotisations.Paiement.PAYMENT_TYPES[0][0],
|
|
)
|
|
cls.cotisations_facture_1 = cotisations.Facture.objects.create(
|
|
user=cls.users_user_1, # Dep users.User
|
|
paiement=cls.cotisations_paiement_1, # Dep cotisations.Paiement
|
|
banque=cls.cotisations_banque_1, # Dep cotisations.Banque
|
|
cheque="1234567890",
|
|
date=datetime.datetime.now(datetime.timezone.utc),
|
|
valid=True,
|
|
control=False,
|
|
)
|
|
cls.cotisations_vente_1 = cotisations.Vente.objects.create(
|
|
facture=cls.cotisations_facture_1, # Dep cotisations.Facture
|
|
number=2,
|
|
name="cotisations_vente_1",
|
|
prix=10,
|
|
duration=1,
|
|
type_cotisation=cotisations.Vente.COTISATION_TYPE[0][0],
|
|
)
|
|
# A cotisation is automatically created by the Vente object and
|
|
# trying to create another cotisation associated with this vente
|
|
# will fail so we simply retrieve it so it can be used in the tests
|
|
cls.cotisations_cotisation_1 = cotisations.Cotisation.objects.get(
|
|
vente=cls.cotisations_vente_1 # Dep cotisations.Vente
|
|
)
|
|
cls.machines_machine_1 = machines.Machine.objects.create(
|
|
user=cls.users_user_1, # Dep users.User
|
|
name="machines_machine_1",
|
|
active=True,
|
|
)
|
|
cls.machines_ouvertureportlist_1 = machines.OuverturePortList.objects.create(
|
|
name="machines_ouvertureportlist_1"
|
|
)
|
|
cls.machines_soa_1 = machines.SOA.objects.create(
|
|
name="machines_soa_1",
|
|
mail="postmaster@example.net",
|
|
refresh=86400,
|
|
retry=7200,
|
|
expire=3600000,
|
|
ttl=172800,
|
|
)
|
|
cls.machines_extension_1 = machines.Extension.objects.create(
|
|
name="machines_extension_1",
|
|
need_infra=False,
|
|
# Do not set origin because of circular dependency
|
|
origin_v6="2001:db8:1234::",
|
|
soa=cls.machines_soa_1, # Dep machines.SOA
|
|
)
|
|
cls.machines_vlan_1 = machines.Vlan.objects.create(
|
|
vlan_id=0, name="machines_vlan_1", comment="machines Vlan 1"
|
|
)
|
|
cls.machines_iptype_1 = machines.IpType.objects.create(
|
|
type="machines_iptype_1",
|
|
extension=cls.machines_extension_1, # Dep machines.Extension
|
|
need_infra=False,
|
|
domaine_ip_start="10.0.0.1",
|
|
domaine_ip_stop="10.0.0.255",
|
|
prefix_v6="2001:db8:1234::",
|
|
vlan=cls.machines_vlan_1, # Dep machines.Vlan
|
|
ouverture_ports=cls.machines_ouvertureportlist_1, # Dep machines.OuverturePortList
|
|
)
|
|
# All IPs in the IpType range are autocreated so we can't create
|
|
# new ones and thus we only retrieve it if needed in the tests
|
|
cls.machines_iplist_1 = machines.IpList.objects.get(
|
|
ipv4="10.0.0.1", ip_type=cls.machines_iptype_1 # Dep machines.IpType
|
|
)
|
|
cls.machines_machinetype_1 = machines.MachineType.objects.create(
|
|
type="machines_machinetype_1",
|
|
ip_type=cls.machines_iptype_1, # Dep machines.IpType
|
|
)
|
|
cls.machines_interface_1 = machines.Interface.objects.create(
|
|
ipv4=cls.machines_iplist_1, # Dep machines.IpList
|
|
mac_address="00:00:00:00:00:00",
|
|
machine=cls.machines_machine_1, # Dep machines.Machine
|
|
type=cls.machines_machinetype_1, # Dep machines.MachineType
|
|
details="machines Interface 1",
|
|
# port_lists=[cls.machines_ouvertureportlist_1] # Dep machines.OuverturePortList
|
|
)
|
|
cls.machines_domain_1 = machines.Domain.objects.create(
|
|
interface_parent=cls.machines_interface_1, # Dep machines.Interface
|
|
name="machinesdomain",
|
|
extension=cls.machines_extension_1 # Dep machines.Extension
|
|
# Do no define cname for circular dependency
|
|
)
|
|
cls.machines_mx_1 = machines.Mx.objects.create(
|
|
zone=cls.machines_extension_1, # Dep machines.Extension
|
|
priority=10,
|
|
name=cls.machines_domain_1, # Dep machines.Domain
|
|
)
|
|
cls.machines_ns_1 = machines.Ns.objects.create(
|
|
zone=cls.machines_extension_1, # Dep machines.Extension
|
|
ns=cls.machines_domain_1, # Dep machines.Domain
|
|
)
|
|
cls.machines_txt_1 = machines.Txt.objects.create(
|
|
zone=cls.machines_extension_1, # Dep machines.Extension
|
|
field1="machines_txt_1",
|
|
field2="machies Txt 1",
|
|
)
|
|
cls.machines_srv_1 = machines.Srv.objects.create(
|
|
service="machines_srv_1",
|
|
protocole=machines.Srv.TCP,
|
|
extension=cls.machines_extension_1, # Dep machines.Extension
|
|
ttl=172800,
|
|
priority=0,
|
|
port=1,
|
|
target=cls.machines_domain_1, # Dep machines.Domain
|
|
)
|
|
cls.machines_ipv6list_1 = machines.Ipv6List.objects.create(
|
|
ipv6="2001:db8:1234::",
|
|
interface=cls.machines_interface_1, # Dep machines.Interface
|
|
slaac_ip=False,
|
|
)
|
|
cls.machines_service_1 = machines.Service.objects.create(
|
|
service_type="machines_service_1",
|
|
min_time_regen=datetime.timedelta(minutes=1),
|
|
regular_time_regen=datetime.timedelta(hours=1)
|
|
# Do not define service_link because circular dependency
|
|
)
|
|
cls.machines_servicelink_1 = machines.Service_link.objects.create(
|
|
service=cls.machines_service_1, # Dep machines.Service
|
|
server=cls.machines_interface_1, # Dep machines.Interface
|
|
last_regen=datetime.datetime.now(datetime.timezone.utc),
|
|
asked_regen=False,
|
|
)
|
|
cls.machines_ouvertureport_1 = machines.OuverturePort.objects.create(
|
|
begin=1,
|
|
end=2,
|
|
port_list=cls.machines_ouvertureportlist_1, # Dep machines.OuverturePortList
|
|
protocole=machines.OuverturePort.TCP,
|
|
io=machines.OuverturePort.OUT,
|
|
)
|
|
cls.machines_nas_1 = machines.Nas.objects.create(
|
|
name="machines_nas_1",
|
|
nas_type=cls.machines_machinetype_1, # Dep machines.MachineType
|
|
machine_type=cls.machines_machinetype_1, # Dep machines.MachineType
|
|
port_access_mode=machines.Nas.AUTH[0][0],
|
|
autocapture_mac=False,
|
|
)
|
|
cls.preferences_service_1 = preferences.Service.objects.create(
|
|
name="preferences_service_1",
|
|
url="https://example.net",
|
|
description="preferences Service 1",
|
|
image="/media/logo/none.png",
|
|
)
|
|
cls.topologie_stack_1 = topologie.Stack.objects.create(
|
|
name="topologie_stack_1",
|
|
stack_id="1",
|
|
details="topologie Stack 1",
|
|
member_id_min=1,
|
|
member_id_max=10,
|
|
)
|
|
cls.topologie_accespoint_1 = topologie.AccessPoint.objects.create(
|
|
user=cls.users_user_1, # Dep users.User
|
|
name="machines_machine_1",
|
|
active=True,
|
|
location="topologie AccessPoint 1",
|
|
)
|
|
cls.topologie_server_1 = topologie.Server.objects.create(
|
|
user=cls.users_user_1, # Dep users.User
|
|
name="machines_machine_1",
|
|
active=True,
|
|
)
|
|
cls.topologie_building_1 = topologie.Building.objects.create(
|
|
name="topologie_building_1"
|
|
)
|
|
cls.topologie_switchbay_1 = topologie.SwitchBay.objects.create(
|
|
name="topologie_switchbay_1",
|
|
building=cls.topologie_building_1, # Dep topologie.Building
|
|
info="topologie SwitchBay 1",
|
|
)
|
|
cls.topologie_constructorswitch_1 = topologie.ConstructorSwitch.objects.create(
|
|
name="topologie_constructorswitch_1"
|
|
)
|
|
cls.topologie_modelswitch_1 = topologie.ModelSwitch.objects.create(
|
|
reference="topologie_modelswitch_1",
|
|
constructor=cls.topologie_constructorswitch_1, # Dep topologie.ConstructorSwitch
|
|
)
|
|
cls.topologie_switch_1 = topologie.Switch.objects.create(
|
|
user=cls.users_user_1, # Dep users.User
|
|
name="machines_machine_1",
|
|
active=True,
|
|
number=10,
|
|
stack=cls.topologie_stack_1, # Dep topologie.Stack
|
|
stack_member_id=1,
|
|
model=cls.topologie_modelswitch_1, # Dep topologie.ModelSwitch
|
|
switchbay=cls.topologie_switchbay_1, # Dep topologie.SwitchBay
|
|
)
|
|
cls.topologie_room_1 = topologie.Room.objects.create(
|
|
name="topologie_romm_1", details="topologie Room 1"
|
|
)
|
|
cls.topologie_port_1 = topologie.Port.objects.create(
|
|
switch=cls.topologie_switch_1, # Dep topologie.Switch
|
|
port=1,
|
|
room=cls.topologie_room_1, # Dep topologie.Room
|
|
radius=topologie.Port.STATES[0][0],
|
|
vlan_force=cls.machines_vlan_1, # Dep machines.Vlan
|
|
details="topologie_switch_1",
|
|
)
|
|
cls.topologie_port_2 = topologie.Port.objects.create(
|
|
switch=cls.topologie_switch_1, # Dep topologie.Switch
|
|
port=2,
|
|
machine_interface=cls.machines_interface_1, # Dep machines.Interface
|
|
radius=topologie.Port.STATES[0][0],
|
|
vlan_force=cls.machines_vlan_1, # Dep machines.Vlan
|
|
details="topologie_switch_1",
|
|
)
|
|
cls.topologie_port_3 = topologie.Port.objects.create(
|
|
switch=cls.topologie_switch_1, # Dep topologie.Switch
|
|
port=3,
|
|
room=cls.topologie_room_1, # Dep topologie.Room
|
|
radius=topologie.Port.STATES[0][0],
|
|
# Do not defines related because circular dependency # Dep machines.Vlan
|
|
details="topologie_switch_1",
|
|
)
|
|
cls.users_ban_1 = users.Ban.objects.create(
|
|
user=cls.users_user_1, # Dep users.User
|
|
raison="users Ban 1",
|
|
date_start=datetime.datetime.now(datetime.timezone.utc),
|
|
date_end=datetime.datetime.now(datetime.timezone.utc)
|
|
+ datetime.timedelta(days=1),
|
|
state=users.Ban.STATES[0][0],
|
|
)
|
|
cls.users_club_1 = users.Club.objects.create(
|
|
password="password",
|
|
last_login=datetime.datetime.now(datetime.timezone.utc),
|
|
surname="users_club_1",
|
|
pseudo="usersclub1",
|
|
email="users_club_1@example.net",
|
|
school=cls.users_school_1, # Dep users.School
|
|
shell=cls.users_listshell_1, # Dep users.ListShell
|
|
comment="users Club 1 comment",
|
|
pwd_ntlm="",
|
|
state=users.User.STATES[0][0],
|
|
registered=datetime.datetime.now(datetime.timezone.utc),
|
|
telephone="0123456789",
|
|
uid_number=21103,
|
|
rezo_rez_uid=21103,
|
|
)
|
|
# Need merge of MR145 to work
|
|
# TODO: Merge !145
|
|
# cls.users_listright_1 = users.ListRight.objects.create(
|
|
# unix_name="userslistright",
|
|
# gid=601,
|
|
# critical=False,
|
|
# details="userslistright"
|
|
# )
|
|
cls.users_serviceuser_1 = users.ServiceUser.objects.create(
|
|
password="password",
|
|
last_login=datetime.datetime.now(datetime.timezone.utc),
|
|
pseudo="usersserviceuser1",
|
|
access_group=users.ServiceUser.ACCESS[0][0],
|
|
comment="users ServiceUser 1",
|
|
)
|
|
cls.users_whitelist_1 = users.Whitelist.objects.create(
|
|
user=cls.users_user_1,
|
|
raison="users Whitelist 1",
|
|
date_start=datetime.datetime.now(datetime.timezone.utc),
|
|
date_end=datetime.datetime.now(datetime.timezone.utc)
|
|
+ datetime.timedelta(days=1),
|
|
)
|
|
|
|
def check_responses_code(self, urls, expected_code, formats=None, assert_more=None):
|
|
"""Utility function to test if a list of urls answer an expected code.
|
|
|
|
Args:
|
|
urls: The list of urls to test
|
|
expected_code: The HTTP return code expected
|
|
formats: The list of formats to use for the request. Default is to
|
|
only test `None` format.
|
|
assert_more: An optional function to assert more specific data in
|
|
the same test. The response object, the url and the format
|
|
used are passed as arguments.
|
|
|
|
Raises:
|
|
AssertionError: The response got did not have the expected status
|
|
code.
|
|
Any exception raised in the evalutation of `assert_more`.
|
|
"""
|
|
if formats is None:
|
|
formats = [None]
|
|
for url in urls:
|
|
for format in formats:
|
|
with self.subTest(url=url, format=format):
|
|
response = self.client.get(url, format=format)
|
|
assert response.status_code == expected_code
|
|
if assert_more is not None:
|
|
assert_more(response, url, format)
|
|
|
|
def test_no_auth_endpoints_with_no_auth(self):
|
|
"""Tests that every endpoint that does not require to be
|
|
authenticated, returns a Ok (200) response when not authenticated.
|
|
|
|
Raises:
|
|
AssertionError: An endpoint did not have a 200 status code.
|
|
"""
|
|
urls = self.no_auth_endpoints
|
|
self.check_responses_code(urls, codes.ok)
|
|
|
|
def test_auth_endpoints_with_no_auth(self):
|
|
"""Tests that every endpoint that does require to be authenticated,
|
|
returns a Unauthorized (401) response when not authenticated.
|
|
|
|
Raises:
|
|
AssertionError: An endpoint did not have a 401 status code.
|
|
"""
|
|
urls = self.auth_no_perm_endpoints + self.auth_perm_endpoints
|
|
self.check_responses_code(urls, codes.unauthorized)
|
|
|
|
def test_no_auth_endpoints_with_auth(self):
|
|
"""Tests that every endpoint that does not require to be
|
|
authenticated, returns a Ok (200) response when authenticated.
|
|
|
|
Raises:
|
|
AssertionError: An endpoint did not have a 200 status code.
|
|
"""
|
|
self.client.force_authenticate(user=self.stduser)
|
|
urls = self.no_auth_endpoints
|
|
self.check_responses_code(urls, codes.ok)
|
|
|
|
def test_auth_no_perm_endpoints_with_auth_and_no_perm(self):
|
|
"""Tests that every endpoint that does require to be authenticated and
|
|
no special permissions, returns a Ok (200) response when authenticated
|
|
but without permissions.
|
|
|
|
Raises:
|
|
AssertionError: An endpoint did not have a 200 status code.
|
|
"""
|
|
self.client.force_authenticate(user=self.stduser)
|
|
urls = self.auth_no_perm_endpoints
|
|
self.check_responses_code(urls, codes.ok)
|
|
|
|
def test_auth_perm_endpoints_with_auth_and_no_perm(self):
|
|
"""Tests that every endpoint that does require to be authenticated and
|
|
special permissions, returns a Forbidden (403) response when
|
|
authenticated but without permissions.
|
|
|
|
Raises:
|
|
AssertionError: An endpoint did not have a 403 status code.
|
|
"""
|
|
self.client.force_authenticate(user=self.stduser)
|
|
urls = self.auth_perm_endpoints
|
|
self.check_responses_code(urls, codes.forbidden)
|
|
|
|
def test_auth_endpoints_with_auth_and_perm(self):
|
|
"""Tests that every endpoint that does require to be authenticated,
|
|
returns a Ok (200) response when authenticated with all permissions.
|
|
|
|
Raises:
|
|
AssertionError: An endpoint did not have a 200 status code.
|
|
"""
|
|
self.client.force_authenticate(user=self.superuser)
|
|
urls = self.auth_no_perm_endpoints + self.auth_perm_endpoints
|
|
self.check_responses_code(urls, codes.ok)
|
|
|
|
def test_endpoints_not_found(self):
|
|
"""Tests that every endpoint that uses a primary key parameter,
|
|
returns a Not Found (404) response when queried with non-existing
|
|
primary key.
|
|
|
|
Raises:
|
|
AssertionError: An endpoint did not have a 404 status code.
|
|
"""
|
|
self.client.force_authenticate(user=self.superuser)
|
|
# Select only the URLs with '<pk>' and replace it with '42'
|
|
urls = self.not_found_endpoints
|
|
self.check_responses_code(urls, codes.not_found)
|
|
|
|
def test_formats(self):
|
|
"""Tests that every endpoint returns a Ok (200) response when using
|
|
different formats. Also checks that 'json' format returns a valid
|
|
JSON object.
|
|
|
|
Raises:
|
|
AssertionError: An endpoint did not have a 200 status code.
|
|
"""
|
|
self.client.force_authenticate(user=self.superuser)
|
|
|
|
urls = (
|
|
self.no_auth_endpoints
|
|
+ self.auth_no_perm_endpoints
|
|
+ self.auth_perm_endpoints
|
|
)
|
|
|
|
def assert_more(response, url, format):
|
|
"""Assert the response is valid json when format is json"""
|
|
if format is "json":
|
|
json.loads(response.content.decode())
|
|
|
|
self.check_responses_code(
|
|
urls, codes.ok, formats=[None, "json", "api"], assert_more=assert_more
|
|
)
|
|
|
|
|
|
class APIPaginationTestCase(APITestCase):
|
|
"""Test case to check that the pagination is used on all endpoints that
|
|
should use it.
|
|
|
|
Attributes:
|
|
endpoints: A list of endpoints that should use the pagination.
|
|
superuser: A superuser used in the tests to access the endpoints.
|
|
"""
|
|
|
|
endpoints = [
|
|
"/api/cotisations/article/",
|
|
"/api/cotisations/banque/",
|
|
"/api/cotisations/cotisation/",
|
|
"/api/cotisations/facture/",
|
|
"/api/cotisations/paiement/",
|
|
"/api/cotisations/vente/",
|
|
"/api/machines/domain/",
|
|
"/api/machines/extension/",
|
|
"/api/machines/interface/",
|
|
"/api/machines/iplist/",
|
|
"/api/machines/iptype/",
|
|
"/api/machines/ipv6list/",
|
|
"/api/machines/machine/",
|
|
"/api/machines/machinetype/",
|
|
"/api/machines/mx/",
|
|
"/api/machines/nas/",
|
|
"/api/machines/ns/",
|
|
"/api/machines/ouvertureportlist/",
|
|
"/api/machines/ouvertureport/",
|
|
"/api/machines/servicelink/",
|
|
"/api/machines/service/",
|
|
"/api/machines/soa/",
|
|
"/api/machines/srv/",
|
|
"/api/machines/txt/",
|
|
"/api/machines/vlan/",
|
|
"/api/preferences/service/",
|
|
"/api/topologie/acesspoint/",
|
|
"/api/topologie/building/",
|
|
"/api/topologie/constructorswitch/",
|
|
"/api/topologie/modelswitch/",
|
|
"/api/topologie/room/",
|
|
"/api/topologie/server/",
|
|
"/api/topologie/stack/",
|
|
"/api/topologie/switch/",
|
|
"/api/topologie/switchbay/",
|
|
"/api/topologie/switchport/",
|
|
"/api/users/adherent/",
|
|
"/api/users/ban/",
|
|
"/api/users/club/",
|
|
"/api/users/listright/",
|
|
"/api/users/school/",
|
|
"/api/users/serviceuser/",
|
|
"/api/users/shell/",
|
|
"/api/users/user/",
|
|
"/api/users/whitelist/",
|
|
"/api/dns/zones/",
|
|
"/api/dhcp/hostmacip/",
|
|
"/api/mailing/standard",
|
|
"/api/mailing/club",
|
|
"/api/services/regen/",
|
|
]
|
|
superuser = None
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
# A user with all the rights
|
|
# We need to use a different username than for the first
|
|
# test case because TestCase is using rollbacks which don't
|
|
# trigger the ldap_sync() thus the LDAP still have data about
|
|
# the old users.
|
|
cls.superuser = users.User.objects.create_superuser(
|
|
"apisuperuser2",
|
|
"apisuperuser2",
|
|
"apisuperuser2@example.net",
|
|
"apisuperuser2",
|
|
)
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
cls.superuser.delete()
|
|
super(APIPaginationTestCase, self).tearDownClass()
|
|
|
|
def test_pagination(self):
|
|
"""Tests that every endpoint is using the pagination correctly.
|
|
|
|
Raises:
|
|
AssertionError: An endpoint did not have one the following keyword
|
|
in the JSOn response: 'count', 'next', 'previous', 'results'
|
|
or more that 100 results were returned.
|
|
"""
|
|
self.client.force_authenticate(self.superuser)
|
|
for url in self.endpoints:
|
|
with self.subTest(url=url):
|
|
response = self.client.get(url, format="json")
|
|
res_json = json.loads(response.content.decode())
|
|
assert "count" in res_json.keys()
|
|
assert "next" in res_json.keys()
|
|
assert "previous" in res_json.keys()
|
|
assert "results" in res_json.keys()
|
|
assert not len("results") > 100
|