From 2027397e0357c217b906d9c5ccb9a7e1ce5bed3a Mon Sep 17 00:00:00 2001 From: paulmart-n Date: Mon, 3 Jun 2024 11:51:05 +0200 Subject: [PATCH] Whitebox Tests --- fetchDUALIS.py | 5 ++++- fetchRAPLA.py | 37 ++++++++++++++++++++++++++++++------- requirements.txt | 4 +++- routing.py | 2 +- tests_examples/test_app.py | 37 ++++++++++++++++++++++++++++++++----- 5 files changed, 70 insertions(+), 15 deletions(-) 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