Skip to content

Commit a974b23

Browse files
Test: Ajout des tests unitaires pour AnalyseurLogApache (#26)
- Création d'un fichier conftest.py qui contient toutes les fixtures et les données générales - Ajout des tests unitaires pour la classe AnalyseurLogApache
1 parent 8aa62d8 commit a974b23

4 files changed

Lines changed: 334 additions & 80 deletions

File tree

tests/conftest.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
"""
2+
Module de configuration des tests unitaires.
3+
"""
4+
5+
import pytest
6+
from cli.parseur_arguments_cli import ParseurArgumentsCLI
7+
from parse.fichier_log_apache import FichierLogApache
8+
from parse.parseur_log_apache import ParseurLogApache
9+
from analyse.analyseur_log_apache import AnalyseurLogApache
10+
11+
12+
# -----------------
13+
# Données générales
14+
# -----------------
15+
16+
# Lignes respectant la syntaxe d'un fichier de log Apache
17+
lignes_valides = [
18+
'192.168.1.1 - - [12/Jan/2025:10:15:32 +0000] "GET /index.html HTTP/1.1" 200 532',
19+
20+
'::1 - - [05/Mar/2025:16:59:43 +0100] "POST / HTTP/1.1" 500 20'
21+
'"http://localhost/connexion.php" "Mozilla/5.0 (Windows NT 10.0;'
22+
' Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"',
23+
24+
'::1 - - [05/Mar/2025:16:59:43 +0100] "DELETE /index.html HTTP/2.1" 500 20',
25+
26+
'::1 - test [05/Mar/2025:16:59:59 +0100] "DELETE /index.html HTTP/2.1" 500 20',
27+
28+
'111.89.7.3 - essaie [27/Feb/2025:10:0:0 +0110] "GET / HTTP/2.1" 500 20'
29+
]
30+
31+
# Lignes ne respectant pas la syntaxe d'un fichier de log Apache
32+
lignes_invalides = [
33+
'',
34+
35+
'Une ligne avec un format invalide !',
36+
37+
'::1 - - [05/Mar/2025:16:59:43] "DELETE / HTTP/2.1" 200 20',
38+
39+
'192.168.1.1 - [12/Jan/2025:10:15:32 +0000] "GET /index.html HTTP/1.1" test 532'
40+
]
41+
42+
# ------------------
43+
# Fixtures générales
44+
# ------------------
45+
46+
@pytest.fixture
47+
def parseur_arguments_cli():
48+
"""
49+
Fixture pour initialiser le parseur d'arguments CLI.
50+
Returns:
51+
ParseurArgumentsCLI: Une instance de la classe :class:`ParseurArgumentsCLI`.
52+
"""
53+
return ParseurArgumentsCLI()
54+
55+
@pytest.fixture()
56+
def log_apache(tmp_path):
57+
"""
58+
Fixture pour créer et récupérer un fichier de log Apache temporaire.
59+
Elle permet de générer un fichier de log Apache temporaire contenant
60+
soit des lignes valides, soit des lignes invalides selon le paramètre fourni.
61+
Args:
62+
tmp_path (Path): Chemin temporaire fourni par pytest.
63+
Returns:
64+
Callable[[bool], Path]: Une fonction qui crée et retourne le chemin
65+
du fichier de log temporaire.
66+
"""
67+
def _creer_log(valide):
68+
"""
69+
Crée un fichier de log Apache temporaire.
70+
Args:
71+
valide (bool): Si ``True``, le fichier contient des lignes de log valides.
72+
Sinon, il contient des lignes invalides.
73+
Returns:
74+
Path: Le chemin du fichier de log temporaire créé.
75+
"""
76+
contenu = (
77+
"\n".join(lignes_valides)
78+
if valide == True
79+
else "\n".join(lignes_invalides)
80+
)
81+
fichier_temp = tmp_path / "access.log"
82+
fichier_temp.write_text(contenu)
83+
return fichier_temp
84+
return _creer_log
85+
86+
@pytest.fixture
87+
def parseur_log_apache(log_apache, request):
88+
"""
89+
Fixture pour initialiser un parseur de fichier de log Apache.
90+
Args:
91+
log_apache: La fixture pour initialiser un fichier temporaire.
92+
request: Paramètre de la fonction. Si il est égale à ``False``, cette fixture
93+
retourne un parseur de log Apache qui analyse un fichier avec un format
94+
invalide. Sinon, retourne un parseur de log Apache qui analyse un fichier
95+
avec un format valide.
96+
Returns:
97+
ParseurLogApache: Une instance de la classe :class:`ParseurLogApache`.
98+
"""
99+
if hasattr(request, "param") and request.param == False:
100+
return ParseurLogApache(log_apache(False))
101+
return ParseurLogApache(log_apache(True))
102+
103+
@pytest.fixture()
104+
def fichier_log_apache(parseur_log_apache):
105+
"""
106+
Fixture pour initialiser une représentation d'un fichier de log Apache.
107+
Cette représentation comprend par défaut les entrées parsées de la liste
108+
``lignes_valides``.
109+
Returns:
110+
FichierLogApache: Une instance de la classe :class:`FichierLogApache`.
111+
"""
112+
return parseur_log_apache.parse_fichier()
113+
114+
@pytest.fixture()
115+
def analyseur_log_apache(fichier_log_apache):
116+
"""
117+
Fixture pour initialiser un analyseur statistique de fichier de log Apache.
118+
Le fichier qu'analyse cet analyseur comprend par défaut les entrées parsées de la liste
119+
``lignes_valides``.
120+
Returns:
121+
AnalyseurLogApache: Une instance de la classe :class:`AnalyseurLogApache`.
122+
"""
123+
return AnalyseurLogApache(fichier_log_apache)

tests/test_analyseur_log_apache.py

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
"""
2+
Modules des tests unitaires pour l'analyse statistique d'un fichier de log Apache.
3+
"""
4+
5+
import pytest
6+
from parse.fichier_log_apache import FichierLogApache
7+
from analyse.analyseur_log_apache import AnalyseurLogApache
8+
9+
# Tests unitaires
10+
11+
@pytest.mark.parametrize("fichier, nombre_par_top", [
12+
(False, 3),
13+
(FichierLogApache("test.log"), False)
14+
])
15+
def test_analyseur_exception_type_invalide(fichier, nombre_par_top):
16+
"""
17+
Vérifie que la classe AnalyseurLogApache lève une :class:`TypeError` si les types des
18+
paramètres du constructeur sont invalides.
19+
20+
Scénarios testés:
21+
- Type incorrect pour le paramètre ``fichier``.
22+
- Type incorrect pour le paramètre ``nombre_par_top``.
23+
24+
Args:
25+
fichier (any): Représentation du fichier log.
26+
nombre_par_top (any): Nombre maximum d'éléments dans le top classement.
27+
"""
28+
with pytest.raises(TypeError):
29+
analyseur = AnalyseurLogApache(fichier, nombre_par_top)
30+
31+
def test_analyseur_exception_valeur_nombre_par_top_invalide():
32+
"""
33+
Vérifie que la classe AnalyseurLogApache lève une :class:`ValueError` si le
34+
paramètre ``nombre_par_top`` du constructeur est un entier négatif.
35+
36+
Scénarios testés:
37+
- Nombre négatif pour ``nombre_par_top``.
38+
"""
39+
with pytest.raises(ValueError):
40+
analyseur = AnalyseurLogApache(FichierLogApache("test.log"), -4)
41+
42+
@pytest.mark.parametrize("liste_elements, nom_element, mode_top_classement", [
43+
(0, "test", True),
44+
([], 0, True),
45+
([], "test", 0)
46+
])
47+
def test_analyseur_exception_repartition_elements_type_invalide(analyseur_log_apache,
48+
liste_elements,
49+
nom_element,
50+
mode_top_classement):
51+
"""
52+
Vérifie que _get_repartition_elements lève une :class:`TypeError` si les types sont invalides.
53+
54+
Scénarios testés:
55+
- ``liste_elements`` n'est pas une ``list``.
56+
- ``nom_element`` n'est pas un ``str``.
57+
- ``mode_top_classement`` n'est pas un ``bool``.
58+
59+
Args:
60+
analyseur_log_apache (AnalyseurLogApache): Fixture pour l'instance
61+
de la classe ``ParseurLogApache``.
62+
liste_elements (any): Liste des éléments à répartir.
63+
nom_element (any): Nom des éléments à analyser.
64+
mode_top_classement (any): Mode top-classement activé ou non.
65+
"""
66+
with pytest.raises(TypeError):
67+
analyseur_log_apache._get_repartition_elements(liste_elements,
68+
nom_element,
69+
mode_top_classement)
70+
71+
@pytest.mark.parametrize("liste_elements, nom_element, resultat_attendu", [
72+
([1] * 6 + [2] * 4, "chiffre", [
73+
{"chiffre": 1, "total": 6, "taux": 60.0},
74+
{"chiffre": 2, "total": 4, "taux": 40.0}
75+
]),
76+
(["GET"] * 1 + ["POST"] * 7 + ["DELETE"] * 2, "methode", [
77+
{"methode": "POST", "total": 7, "taux": 70.0},
78+
{"methode": "DELETE", "total": 2, "taux": 20.0},
79+
{"methode": "GET", "total": 1, "taux": 10.0}
80+
]),
81+
])
82+
def test_analyseur_repartition_elements_valide(analyseur_log_apache,
83+
liste_elements,
84+
nom_element,
85+
resultat_attendu):
86+
"""
87+
Vérifie la répartition correcte des éléments dans ``_get_repartition_elements``.
88+
89+
Scénarios testés:
90+
- Répartition de chiffres avec deux valeurs fréquentes.
91+
- Répartition de méthodes HTTP avec trois valeurs fréquentes.
92+
93+
Asserts:
94+
- La liste est triée dans l'ordre attendu.
95+
- Le nombre d'éléments dans le résultat correspond à celui attendu.
96+
- Les totaux et les taux sont correctement calculés.
97+
98+
Args:
99+
analyseur_log_apache (AnalyseurLogApache): Fixture pour l'instance
100+
de la classe ``ParseurLogApache``.
101+
liste_elements (list): Liste des éléments à analyser.
102+
nom_element (str): Nom de l'élément à analyser.
103+
resultat_attendu (list): Résultat attendu après répartition.
104+
"""
105+
repartitions = analyseur_log_apache._get_repartition_elements(
106+
liste_elements, nom_element
107+
)
108+
assert len(repartitions) == len(resultat_attendu)
109+
for repartition, resultat in zip(repartitions, resultat_attendu):
110+
assert repartition[nom_element] == resultat[nom_element]
111+
assert repartition["total"] == resultat["total"]
112+
assert repartition["taux"] == resultat["taux"]
113+
114+
@pytest.mark.parametrize("liste_elements, nom_element, nombre_top, resultat_attendu", [
115+
([1] * 6 + [2] * 4, "chiffre", 1, [
116+
{"chiffre": 1, "total": 6, "taux": 60.0}
117+
]),
118+
(["GET"] * 1 + ["POST"] * 7 + ["DELETE"] * 2, "methode", 2, [
119+
{"methode": "POST", "total": 7, "taux": 70.0},
120+
{"methode": "DELETE", "total": 2, "taux": 20.0}
121+
]),
122+
])
123+
def test_analyseur_repartition_mode_top_elements_valide(analyseur_log_apache,
124+
liste_elements,
125+
nom_element,
126+
nombre_top,
127+
resultat_attendu):
128+
"""
129+
Vérifie que ``_get_repartition_elements`` retourne les top éléments correctement.
130+
131+
Scénarios testés:
132+
- Classement des chiffres avec un seul élément dans le top.
133+
- Classement des méthodes HTTP avec deux éléments dans le top.
134+
135+
Asserts:
136+
- Le nombre de top éléments retournés correspond à ``nombre_top``.
137+
- Les totaux et les taux sont correctement calculés.
138+
139+
Args:
140+
analyseur_log_apache (AnalyseurLogApache): Fixture pour l'instance
141+
de la classe ``ParseurLogApache``.
142+
liste_elements (list): Liste des éléments à analyser.
143+
nom_element (str): Nom de l'élément à analyser.
144+
nombre_top (int): Nombre maximum d'éléments à retourner.
145+
resultat_attendu (list): Résultat attendu.
146+
"""
147+
analyseur_log_apache.nombre_par_top = nombre_top
148+
repartitions = analyseur_log_apache._get_repartition_elements(
149+
liste_elements, nom_element, True
150+
)
151+
assert len(repartitions) == len(resultat_attendu)
152+
for repartition, resultat in zip(repartitions, resultat_attendu):
153+
assert repartition[nom_element] == resultat[nom_element]
154+
assert repartition["total"] == resultat["total"]
155+
assert repartition["taux"] == resultat["taux"]
156+
157+
158+
def test_analyseur_top_urls_valide(analyseur_log_apache):
159+
"""
160+
Vérifie que la méthode ``get_top_urls`` retourne correctement les URLs les plus fréquentées.
161+
162+
Scénarios testés:
163+
- Vérification du tri et du calcul du taux de fréquence.
164+
165+
Asserts:
166+
- La liste est triée dans l'ordre attendu.
167+
- Le nombre d'éléments dans le résultat correspond à celui attendu.
168+
169+
Args:
170+
analyseur_log_apache (AnalyseurLogApache): Fixture pour l'instance
171+
de la classe ParseurLogApache.
172+
"""
173+
top_urls = analyseur_log_apache.get_top_urls()
174+
assert len(top_urls) == 2
175+
assert top_urls[0]["url"] == "/index.html"
176+
assert top_urls[0]["total"] == 3
177+
assert top_urls[0]["taux"] == 60.0
178+
assert top_urls[1]["url"] == "/"
179+
assert top_urls[1]["total"] == 2
180+
assert top_urls[1]["taux"] == 40.0
181+
182+
def test_analyseur_repartition_code_statut_htpp_valide(analyseur_log_apache):
183+
"""
184+
Vérifie que ``get_total_par_code_statut_http`` retourne la répartition correcte des codes HTTP.
185+
186+
Scénarios testés:
187+
- Vérification du tri et du calcul du taux de fréquence.
188+
189+
Asserts:
190+
- La liste est triée dans l'ordre attendu.
191+
- Le nombre d'éléments dans le résultat correspond à celui attendu.
192+
193+
Args:
194+
analyseur_log_apache (AnalyseurLogApache): Fixture pour l'instance
195+
de la classe ParseurLogApache.
196+
"""
197+
repartition = analyseur_log_apache.get_total_par_code_statut_http()
198+
assert len(repartition) == 2
199+
assert repartition[0]["code"] == 500
200+
assert repartition[0]["total"] == 4
201+
assert repartition[0]["taux"] == 80.0
202+
assert repartition[1]["code"] == 200
203+
assert repartition[1]["total"] == 1
204+
assert repartition[1]["taux"] == 20.0

tests/test_parseur_arguments_cli.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,10 @@
33
"""
44

55
import pytest
6-
from cli.parseur_arguments_cli import ParseurArgumentsCLI, ArgumentCLIException
6+
from cli.parseur_arguments_cli import ArgumentCLIException
77

8-
# Données utilisées pour les tests unitaires
98

10-
@pytest.fixture
11-
def parseur_arguments_cli():
12-
"""
13-
Fixture pour initialiser le parseur d'arguments CLI.
14-
Retourne une instance de la classe ParseurArgumentsCLI pour être utilisée dans les tests.
15-
Returns:
16-
ParseurArgumentsCLI: Une instance de la classe ParseurArgumentsCLI.
17-
"""
18-
return ParseurArgumentsCLI()
9+
# Données utilisées pour les tests unitaires
1910

2011
chemins_valides = [
2112
"fichier.log",

0 commit comments

Comments
 (0)