diff --git a/fetchDUALIS.py b/fetchDUALIS.py
index 6c4d762..5c3f329 100644
--- a/fetchDUALIS.py
+++ b/fetchDUALIS.py
@@ -57,7 +57,10 @@ async def getKurs(token: int, cookie: str):
response = await s.get(url=f"{url}?APPNAME=CampusNet&PRGNAME=COURSERESULTS&ARGUMENTS=-N{token},-N000307,",
headers=headers)
html = BeautifulSoup(response.text, 'lxml')
- link = html.body.find('a', attrs={'id': "Popup_details0001"})['href']
+ try:
+ link = html.body.find('a', attrs={'id': "Popup_details0001"})['href']
+ except TypeError:
+ return 0
response = await s.get(url=f"{url}{link[21:]}", headers=headers)
html = BeautifulSoup(response.text, 'lxml')
content = html.body.find('td', attrs={'class': 'level02'}).text
diff --git a/fetchRAPLA.py b/fetchRAPLA.py
index b71d7e7..f591ce0 100644
--- a/fetchRAPLA.py
+++ b/fetchRAPLA.py
@@ -1,4 +1,5 @@
import urllib.error
+from datetime import datetime, timedelta
from dateutil.parser import *
@@ -6,6 +7,7 @@ import asyncio
import httpx
import icalendar
+from dateutil.relativedelta import relativedelta
from icalendar import Calendar, Event
import json
@@ -29,6 +31,7 @@ def writeToFile(filename, data):
:param data:
"""
with open(filename, 'w+') as file:
+ assert "BEGIN:VCALENDAR" in data.text
file.write(data.text)
file.close()
@@ -51,7 +54,7 @@ def parseRaplaURL(url: str):
Konvertiert werden: http, www.; page=calendar \n
In: https; page=ical
:param url:
- :return str:
+ :return [Status: int, URL: str]:
"""
rapla = url.find("rapla.")
if rapla == -1:
@@ -75,31 +78,44 @@ def parseRaplaURL(url: str):
return 0, 0
-async def getNewRapla(url: str):
+async def getNewRapla(url: str, testing=None):
"""
Speichert den iCal eines Raplas auf dem Server. \n
Gibt Namen der Datei zurück. \n
TODO: Standort zu Dateibezeichner hinzufügen, um Konflikte zu vermeiden.
:param url:
+ :param opt. testing:
:return str:
"""
parsed = parseRaplaURL(url)
+
+ if testing:
+ assert "https" in parsed[1]
+ try:
+ assert "ical" in parsed[1]
+ except AssertionError:
+ assert "key" in parsed[1]
+
if parsed[0] == 0:
return 0
elif parsed[0] == 1:
url = parsed[1]
elif parsed[0] == 2:
- return await buildICALfromKey(parsed[1], onlyUpdate=False)
+ return await buildICALfromKey(parsed[1], onlyUpdate=False, testing=True)
fileInURL = url.find("file=")
kurs = url[fileInURL + 5:].upper()
if url[-5:] != ".ical":
try:
async with httpx.AsyncClient() as s:
response = await fetchPlan(s, url)
+ if testing:
+ assert "Vollmer" in response.text
writeToFile(f"calendars/rapla{kurs}.ical", response)
except urllib.error.URLError:
return -1
writeKursToDB(kurs, url)
+ if testing:
+ assert "TINF22B3" in Rapla.query.filter(Rapla.name == "TINF22B3").first().file
return f"rapla{kurs}.ical"
else:
return url
@@ -159,11 +175,12 @@ def raplaSchedule():
asyncio.run(refreshRapla())
-async def buildICALfromKey(url, onlyUpdate):
+async def buildICALfromKey(url, onlyUpdate, testing=True):
"""
Baut eine .ical-Datei aus der mitgegebenen URL, die ein Key-Parameter enthalten muss.
:param url:
:param onlyUpdate:
+ :param opt. testing:
:return Dateinamen:
"""
async with httpx.AsyncClient() as s:
@@ -179,14 +196,18 @@ async def buildICALfromKey(url, onlyUpdate):
return 200
else:
kursname = page.text[page.text.find("
") + 7:page.text.find("")]
+ if testing:
+ assert "TMT22B1" in kursname
if len(kursname) > 15:
return 0
- start = "2024-08-01"
- end = "2024-12-31"
+ start = f'{(datetime.now() - relativedelta(days=183)):%Y-%m-%d}'
+ end = f'{(datetime.now() + relativedelta(days=183)):%Y-%m-%d}'
payload = {"url": url, "start": start, "end": end}
req = await s.post(url="https://dh-api.paulmartin.cloud/rapla", data=payload,
- headers={'Content-Type': 'application/x-www-form-urlencoded'}, timeout=10)
+ headers={'Content-Type': 'application/x-www-form-urlencoded'}, timeout=15)
jsonresp = json.loads(req.text)
+ if testing:
+ assert len(jsonresp) > 0
cal = Calendar()
cal.add('prodid', '-//Rapla//iCal Plugin//EN')
cal.add('version', '2.0')
@@ -211,6 +232,8 @@ async def buildICALfromKey(url, onlyUpdate):
f.close()
if not onlyUpdate:
writeKursToDB(kursname, url)
+ if testing:
+ assert "TMT22B1" in Rapla.query.filter(Rapla.name == "TMT22B1").first().file
return f"rapla{kursname}.ical"
else:
return 200
diff --git a/requirements.txt b/requirements.txt
index 64bbc88..51da94e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -19,4 +19,6 @@ pymysql
APScheduler
cryptography
python-dateutil~=2.9.0.post0
-requests~=2.31.0
\ No newline at end of file
+requests~=2.31.0
+pytest
+pytest-asyncio
\ No newline at end of file
diff --git a/routing.py b/routing.py
index 7d02884..d81a83e 100644
--- a/routing.py
+++ b/routing.py
@@ -101,7 +101,7 @@ def initRoutes(app: Flask):
s="p", praxis="hidden")
@app.route("/plan/")
- async def displayPlan(kurs):
+ async def displayPlan(kurs: str):
"""
Zeigt den Stundenplan ohne Login an. \n
Präferenzen werden nicht berücksichtigt.
diff --git a/tests_examples/test_app.py b/tests_examples/test_app.py
index 1beda67..5e1695f 100644
--- a/tests_examples/test_app.py
+++ b/tests_examples/test_app.py
@@ -1,6 +1,7 @@
import pytest
from bs4 import BeautifulSoup
+import fetchRAPLA
import routing
import init
from tests_examples import login_data
@@ -45,7 +46,7 @@ def login(client):
return False
-def test_login(client):
+def test_login_blackbox(client):
"""
Testet die Login-Funktion
:param client:
@@ -63,7 +64,7 @@ def test_login(client):
assert len(cookie.value) == 32 # CNSC-Länge: 32 → Wenn der Cookie so lang ist, ist man erfolgreich eingeloggt.
-def test_kurssetup(client):
+def test_kurssetup_blackbox(client):
"""
Testet die Konfiguration eines Kurses
:param client:
@@ -86,7 +87,7 @@ def test_kurssetup(client):
assert False
-def test_semestersetup(client):
+def test_semestersetup_blackbox(client):
"""
Testet die Konfiguration eines Semesters
:param client:
@@ -106,7 +107,7 @@ def test_semestersetup(client):
assert False
-def test_noten(client):
+def test_noten_blackbox(client):
"""
Testet das Abrufen der Noten aus zwei verschiedenen Semestern
:param client:
@@ -134,7 +135,7 @@ def test_noten(client):
assert False
-def test_logout(client):
+def test_logout_blackbox(client):
"""
Testet die Logout-Funktion
:param client:
@@ -147,3 +148,29 @@ def test_logout(client):
assert len(cookie.value) != 32 # CNSC-Länge: 32 → CNSC darf ausgeloggt nicht gesetzt sein
else:
assert False
+
+
+@pytest.mark.asyncio()
+async def test_url_anweisung_whitebox(app):
+ """
+ Testet einen Pfad des URL-Imports
+ :param app:
+ """
+ with app.app_context():
+ rapla = await fetchRAPLA.getNewRapla("http://www.rapla.dhbw-karlsruhe.de/rapla?page=calendar&user=vollmer"
+ "&file=tinf22b3", True)
+ assert "TINF22B3" in rapla
+
+
+@pytest.mark.asyncio()
+async def test_url_entscheidung_whitebox(app):
+ """
+ Testet alle Pfade des URL-Imports, die mit einer fehlerfreien Datei enden
+ :param app:
+ """
+ with app.app_context():
+ await test_url_anweisung_whitebox(app)
+ rapla = await fetchRAPLA.getNewRapla("http://www.rapla.dhbw-karlsruhe.de/rapla?key=ah9tAVphi"
+ "caj4FqCtMVJchAs9fh0Dt89jA8Td4kEi21V0i2mlUEpycpIVw5jSY5T",
+ True)
+ assert "TMT22B1" in rapla