Whitebox Tests
This commit is contained in:
@ -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,",
|
response = await s.get(url=f"{url}?APPNAME=CampusNet&PRGNAME=COURSERESULTS&ARGUMENTS=-N{token},-N000307,",
|
||||||
headers=headers)
|
headers=headers)
|
||||||
html = BeautifulSoup(response.text, 'lxml')
|
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)
|
response = await s.get(url=f"{url}{link[21:]}", headers=headers)
|
||||||
html = BeautifulSoup(response.text, 'lxml')
|
html = BeautifulSoup(response.text, 'lxml')
|
||||||
content = html.body.find('td', attrs={'class': 'level02'}).text
|
content = html.body.find('td', attrs={'class': 'level02'}).text
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import urllib.error
|
import urllib.error
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from dateutil.parser import *
|
from dateutil.parser import *
|
||||||
|
|
||||||
@ -6,6 +7,7 @@ import asyncio
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import icalendar
|
import icalendar
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
from icalendar import Calendar, Event
|
from icalendar import Calendar, Event
|
||||||
import json
|
import json
|
||||||
|
|
||||||
@ -29,6 +31,7 @@ def writeToFile(filename, data):
|
|||||||
:param data:
|
:param data:
|
||||||
"""
|
"""
|
||||||
with open(filename, 'w+') as file:
|
with open(filename, 'w+') as file:
|
||||||
|
assert "BEGIN:VCALENDAR" in data.text
|
||||||
file.write(data.text)
|
file.write(data.text)
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
@ -51,7 +54,7 @@ def parseRaplaURL(url: str):
|
|||||||
Konvertiert werden: http, www.; page=calendar \n
|
Konvertiert werden: http, www.; page=calendar \n
|
||||||
In: https; page=ical
|
In: https; page=ical
|
||||||
:param url:
|
:param url:
|
||||||
:return str:
|
:return [Status: int, URL: str]:
|
||||||
"""
|
"""
|
||||||
rapla = url.find("rapla.")
|
rapla = url.find("rapla.")
|
||||||
if rapla == -1:
|
if rapla == -1:
|
||||||
@ -75,31 +78,44 @@ def parseRaplaURL(url: str):
|
|||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
|
|
||||||
async def getNewRapla(url: str):
|
async def getNewRapla(url: str, testing=None):
|
||||||
"""
|
"""
|
||||||
Speichert den iCal eines Raplas auf dem Server. \n
|
Speichert den iCal eines Raplas auf dem Server. \n
|
||||||
Gibt Namen der Datei zurück. \n
|
Gibt Namen der Datei zurück. \n
|
||||||
TODO: Standort zu Dateibezeichner hinzufügen, um Konflikte zu vermeiden.
|
TODO: Standort zu Dateibezeichner hinzufügen, um Konflikte zu vermeiden.
|
||||||
:param url:
|
:param url:
|
||||||
|
:param opt. testing:
|
||||||
:return str:
|
:return str:
|
||||||
"""
|
"""
|
||||||
parsed = parseRaplaURL(url)
|
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:
|
if parsed[0] == 0:
|
||||||
return 0
|
return 0
|
||||||
elif parsed[0] == 1:
|
elif parsed[0] == 1:
|
||||||
url = parsed[1]
|
url = parsed[1]
|
||||||
elif parsed[0] == 2:
|
elif parsed[0] == 2:
|
||||||
return await buildICALfromKey(parsed[1], onlyUpdate=False)
|
return await buildICALfromKey(parsed[1], onlyUpdate=False, testing=True)
|
||||||
fileInURL = url.find("file=")
|
fileInURL = url.find("file=")
|
||||||
kurs = url[fileInURL + 5:].upper()
|
kurs = url[fileInURL + 5:].upper()
|
||||||
if url[-5:] != ".ical":
|
if url[-5:] != ".ical":
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient() as s:
|
async with httpx.AsyncClient() as s:
|
||||||
response = await fetchPlan(s, url)
|
response = await fetchPlan(s, url)
|
||||||
|
if testing:
|
||||||
|
assert "Vollmer" in response.text
|
||||||
writeToFile(f"calendars/rapla{kurs}.ical", response)
|
writeToFile(f"calendars/rapla{kurs}.ical", response)
|
||||||
except urllib.error.URLError:
|
except urllib.error.URLError:
|
||||||
return -1
|
return -1
|
||||||
writeKursToDB(kurs, url)
|
writeKursToDB(kurs, url)
|
||||||
|
if testing:
|
||||||
|
assert "TINF22B3" in Rapla.query.filter(Rapla.name == "TINF22B3").first().file
|
||||||
return f"rapla{kurs}.ical"
|
return f"rapla{kurs}.ical"
|
||||||
else:
|
else:
|
||||||
return url
|
return url
|
||||||
@ -159,11 +175,12 @@ def raplaSchedule():
|
|||||||
asyncio.run(refreshRapla())
|
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.
|
Baut eine .ical-Datei aus der mitgegebenen URL, die ein Key-Parameter enthalten muss.
|
||||||
:param url:
|
:param url:
|
||||||
:param onlyUpdate:
|
:param onlyUpdate:
|
||||||
|
:param opt. testing:
|
||||||
:return Dateinamen:
|
:return Dateinamen:
|
||||||
"""
|
"""
|
||||||
async with httpx.AsyncClient() as s:
|
async with httpx.AsyncClient() as s:
|
||||||
@ -179,14 +196,18 @@ async def buildICALfromKey(url, onlyUpdate):
|
|||||||
return 200
|
return 200
|
||||||
else:
|
else:
|
||||||
kursname = page.text[page.text.find("<title>") + 7:page.text.find("</title>")]
|
kursname = page.text[page.text.find("<title>") + 7:page.text.find("</title>")]
|
||||||
|
if testing:
|
||||||
|
assert "TMT22B1" in kursname
|
||||||
if len(kursname) > 15:
|
if len(kursname) > 15:
|
||||||
return 0
|
return 0
|
||||||
start = "2024-08-01"
|
start = f'{(datetime.now() - relativedelta(days=183)):%Y-%m-%d}'
|
||||||
end = "2024-12-31"
|
end = f'{(datetime.now() + relativedelta(days=183)):%Y-%m-%d}'
|
||||||
payload = {"url": url, "start": start, "end": end}
|
payload = {"url": url, "start": start, "end": end}
|
||||||
req = await s.post(url="https://dh-api.paulmartin.cloud/rapla", data=payload,
|
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)
|
jsonresp = json.loads(req.text)
|
||||||
|
if testing:
|
||||||
|
assert len(jsonresp) > 0
|
||||||
cal = Calendar()
|
cal = Calendar()
|
||||||
cal.add('prodid', '-//Rapla//iCal Plugin//EN')
|
cal.add('prodid', '-//Rapla//iCal Plugin//EN')
|
||||||
cal.add('version', '2.0')
|
cal.add('version', '2.0')
|
||||||
@ -211,6 +232,8 @@ async def buildICALfromKey(url, onlyUpdate):
|
|||||||
f.close()
|
f.close()
|
||||||
if not onlyUpdate:
|
if not onlyUpdate:
|
||||||
writeKursToDB(kursname, url)
|
writeKursToDB(kursname, url)
|
||||||
|
if testing:
|
||||||
|
assert "TMT22B1" in Rapla.query.filter(Rapla.name == "TMT22B1").first().file
|
||||||
return f"rapla{kursname}.ical"
|
return f"rapla{kursname}.ical"
|
||||||
else:
|
else:
|
||||||
return 200
|
return 200
|
||||||
|
|||||||
@ -19,4 +19,6 @@ pymysql
|
|||||||
APScheduler
|
APScheduler
|
||||||
cryptography
|
cryptography
|
||||||
python-dateutil~=2.9.0.post0
|
python-dateutil~=2.9.0.post0
|
||||||
requests~=2.31.0
|
requests~=2.31.0
|
||||||
|
pytest
|
||||||
|
pytest-asyncio
|
||||||
@ -101,7 +101,7 @@ def initRoutes(app: Flask):
|
|||||||
s="p", praxis="hidden")
|
s="p", praxis="hidden")
|
||||||
|
|
||||||
@app.route("/plan/<string:kurs>")
|
@app.route("/plan/<string:kurs>")
|
||||||
async def displayPlan(kurs):
|
async def displayPlan(kurs: str):
|
||||||
"""
|
"""
|
||||||
Zeigt den Stundenplan ohne Login an. \n
|
Zeigt den Stundenplan ohne Login an. \n
|
||||||
Präferenzen werden nicht berücksichtigt.
|
Präferenzen werden nicht berücksichtigt.
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
import fetchRAPLA
|
||||||
import routing
|
import routing
|
||||||
import init
|
import init
|
||||||
from tests_examples import login_data
|
from tests_examples import login_data
|
||||||
@ -45,7 +46,7 @@ def login(client):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def test_login(client):
|
def test_login_blackbox(client):
|
||||||
"""
|
"""
|
||||||
Testet die Login-Funktion
|
Testet die Login-Funktion
|
||||||
:param client:
|
: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.
|
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
|
Testet die Konfiguration eines Kurses
|
||||||
:param client:
|
:param client:
|
||||||
@ -86,7 +87,7 @@ def test_kurssetup(client):
|
|||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
||||||
def test_semestersetup(client):
|
def test_semestersetup_blackbox(client):
|
||||||
"""
|
"""
|
||||||
Testet die Konfiguration eines Semesters
|
Testet die Konfiguration eines Semesters
|
||||||
:param client:
|
:param client:
|
||||||
@ -106,7 +107,7 @@ def test_semestersetup(client):
|
|||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
||||||
def test_noten(client):
|
def test_noten_blackbox(client):
|
||||||
"""
|
"""
|
||||||
Testet das Abrufen der Noten aus zwei verschiedenen Semestern
|
Testet das Abrufen der Noten aus zwei verschiedenen Semestern
|
||||||
:param client:
|
:param client:
|
||||||
@ -134,7 +135,7 @@ def test_noten(client):
|
|||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
||||||
def test_logout(client):
|
def test_logout_blackbox(client):
|
||||||
"""
|
"""
|
||||||
Testet die Logout-Funktion
|
Testet die Logout-Funktion
|
||||||
:param client:
|
: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
|
assert len(cookie.value) != 32 # CNSC-Länge: 32 → CNSC darf ausgeloggt nicht gesetzt sein
|
||||||
else:
|
else:
|
||||||
assert False
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user