Commit 856f1d65 authored by Andreas Valder's avatar Andreas Valder

Merge branch 'tests' into 'master'

Adds unit tests

See merge request videoagwebsite/videoagwebsite!15
parents 2a003aaf e584b6e9
......@@ -10,3 +10,5 @@ nginx.log
nginx.pid
nginx.conf
uwsgi.sock
.coverage
htmlcov/
......@@ -14,6 +14,11 @@ Hinweis: diese Variante startet eine lokale Testversion der Website, es sind nic
Alternativ, insbesondere zum Testen der Zugriffsbeschränkungen: Siehe `nginx.example.conf`.
### Unittests
Tests können mittels `./tests.py` ausgeführt werden.
Coverage Tests können mittels `rm .coverage; python -m coverage run tests.py; python -m coverage html` ausgeführt werden. Dies erstellt einen Ordner `htmlcov` in dem HTML Output liegt.
### Zum Mitmachen:
1. Repo für den eigenen User forken, dafür den "Fork-Button" auf der Website verwenden
2. Sicherstellen, dass der Upstream richtig konfiguriert ist:
......@@ -39,6 +44,7 @@ Optional (wird für einzelne Features benötigt):
* python-ldap (Login mit Fachschaftsaccount)
* python-icalendar (SoGo-Kalenderimport für Sitzungsankündigungen)
* python-mysql-connector (wenn MySQL als Datenbank verwendet werden soll)
* python-coverage (Für Coverage Tests benötigt)
Kurzform unter Ubuntu:
`sudo apt install python3 python3-flask sqlite python3-requests python3-lxml python3-ldap3 python3-icalendar python3-mysql.connector`
......@@ -11,7 +11,10 @@ def suggest_chapter(lectureid):
time= timedelta(hours=x.hour,minutes=x.minute,seconds=x.second).total_seconds()
time = int(time)
except ValueError:
flash('Falsches Zeitformat, "%H:%M:%S" wird erwartet. Z.B. "01:39:42" für eine Kapitel bei Stunde 1, Minute 39, Sekunde 42')
if 'ref' in request.values:
flash('Falsches Zeitformat, "%H:%M:%S" wird erwartet. Z.B. "01:39:42" für eine Kapitel bei Stunde 1, Minute 39, Sekunde 42')
return redirect(request.values['ref'])
return 'Wrong time format, "%H:%M:%S" is expected', 400
submitter = None
if not ismod():
......
......@@ -30,3 +30,4 @@ LDAP_GROUPS = ['fachschaft']
ERROR_PAGE = 'static/500.html'
RWTH_IP_RANGES = ['134.130.0.0/16', '137.226.0.0/16', '134.61.0.0/16', '192.35.229.0/24', '2a00:8a60::/32']
FSMPI_IP_RANGES = ['137.226.35.192/29', '137.226.75.0/27', '137.226.127.32/27', '137.226.231.192/26', '134.130.102.0/26' ]
DISABLE_SCHEDULER = False
......@@ -23,8 +23,10 @@ if config['DB_ENGINE'] == 'sqlite':
db = sqlite3.connect(config['SQLITE_DB'])
cur = db.cursor()
if config['SQLITE_INIT_SCHEMA']:
print('Init db schema')
cur.executescript(open(config['DB_SCHEMA']).read())
if config['SQLITE_INIT_DATA'] and created:
print('Init db data')
cur.executescript(open(config['DB_DATA']).read())
db.commit()
db.close()
......
......@@ -10,6 +10,8 @@ def legacy_index():
if not courses:
return "Not found", 404
return redirect(url_for('lecture', course=courses[0]['handle'], id=request.args['lectureid']),code=302)
if request.args['view'] == 'faq':
return redirect(url_for('faq'),code=302)
return None
@app.route('/site/')
......
......@@ -27,5 +27,5 @@ def sched_func(delay, priority=0, firstdelay=None, args=[], kargs={}):
print("Scheduler: registered {} (frequency 1/{}s, start delay: {}s)".format(func.__name__, delay, firstdelay))
return func
return wrapper
threading.Thread(target=run_scheduler, daemon=True).start()
if not app.config['DISABLE_SCHEDULER']:
threading.Thread(target=run_scheduler, daemon=True).start()
......@@ -25,6 +25,17 @@ if sys.argv[0].endswith('run.py'):
config['SQLITE_INIT_DATA'] = True
config['DEBUG'] = True
config.from_pyfile('config.py', silent=True)
if sys.argv[0].endswith('tests.py'):
print('running in test mode')
import tempfile
# ensure we always use a clean sqlite db for tests
config['DB_ENGINE'] = 'sqlite'
config['SQLITE_DB'] = tempfile.mktemp(prefix='flasktestingtmp')
print('DB File: {}'.format(config['SQLITE_DB']))
config['SQLITE_INIT_DATA'] = True
config['SQLITE_INIT_SCHEMA'] = True
config['DEBUG'] = True
config['DISABLE_SCHEDULER'] = True
if config['DEBUG']:
app.jinja_env.auto_reload = True
......@@ -338,7 +349,7 @@ def login():
user = userinfo.get('uid')
if not check_mod(user, groups):
flash('Login fehlgeschlagen!')
return render_template('login.html')
return make_response(render_template('login.html'), 403)
session['user'] = userinfo
dbuser = query('SELECT * FROM users WHERE name = ?', user)
if not dbuser:
......
#!/usr/bin/env python3
import os
import unittest
import server
import flask
from flask import url_for
class VideoTestCase(unittest.TestCase):
@classmethod
def tearDownClass(cls):
os.unlink(server.app.config['SQLITE_DB'])
def setUp(self):
server.app.testing = True
self.app = server.app.test_client()
def login(self, c):
with c.session_transaction() as sess:
sess['user'] = {'name': 'videoag', '_csrf_token': 'asd', 'dbid': 72}
sess['_csrf_token'] = 'asd'
def test_index(self):
with self.app as c:
r = c.get('/')
assert r.status_code == 200
self.login(c)
r = c.get('/')
assert r.status_code == 200
def test_courses(self):
with self.app as c:
r = c.get('/courses')
assert r.status_code == 200
self.login(c)
r = c.get('/courses')
assert r.status_code == 200
def test_course(self):
with self.app as c:
# normal
r = c.get('/15ws-afi')
assert r.status_code == 200
# not listed
r = c.get('/15ws-bio')
assert r.status_code == 200
# not visible
r = c.get('/15ws-einfprog')
assert r.status_code == 404
self.login(c)
r = c.get('/15ws-afi')
assert r.status_code == 200
r = c.get('/15ws-einfprog')
assert r.status_code == 200
def test_timetable(self):
with self.app as c:
r = c.get('/internal/timetable')
assert r.status_code == 302
self.login(c)
r = c.get('internal/timetable')
assert r.status_code == 200
r = c.get('internal/timetable?date=2016-W05')
assert r.status_code == 200
assert 'AfI' in r.data.decode()
assert 'Progra' in r.data.decode()
assert 'Bio' in r.data.decode()
def test_faq(self):
r = self.app.get('/faq')
assert r.status_code == 200
def test_ical(self):
with self.app as c:
r = c.get('/internal/ical/all')
assert r.status_code == 401
self.login(c)
r = c.get('/internal/ical/all')
assert r.status_code == 200
assert 'Progra' in r.data.decode()
assert 'Vorlesung' in r.data.decode()
def test_sitemap(self):
r = self.app.get('/sitemap.xml')
assert r.status_code == 200
def test_chapters(self):
with self.app as c:
# wrong time format
r = c.post('/internal/newchapter/7011', data={'text':'testchapter A', 'time': 1234})
assert r.status_code == 400
# should be inserted as id 15
r = c.post('/internal/newchapter/7011', data={'text':'testchapter B', 'time': '00:10:00'})
assert r.status_code == 200
# not yet set visible
r = c.get('/internal/chapters/7011')
assert r.status_code == 404
# other lecture
r = c.get('/internal/chapters/7012')
assert r.status_code == 404
self.login(c)
r = c.post('/internal/edit', data={"chapters.15.visible":1,"_csrf_token":"asd"})
assert r.status_code == 200
r = c.get('/internal/chapters/7011')
assert 'testchapter B' in r.data.decode() and not 'testchapter A' in r.data.decode()
def test_search(self):
r = self.app.get('/search?q=Malo')
assert r.status_code == 200
assert 'Mathematische Logik II' in r.data.decode() and '4.1 Der Sequenzenkalkül' in r.data.decode()
r = self.app.get('/search?q=Afi+Stens')
assert r.status_code == 200
assert 'Analysis für Informatiker' in r.data.decode() and 'Höhere Mathematik I' in r.data.decode()
def test_login(self):
# test login page
r = self.app.get('/internal/login')
assert r.status_code == 200
# test successfull login
with self.app as c:
r = c.post('/internal/login', data={'user': 'videoag', 'password': 'videoag', 'ref': '/'})
assert flask.session['user']
assert r.status_code == 302
assert '<a href="/">' in r.data.decode()
# test unsuccessfull login
with self.app as c:
r = c.post('/internal/login', data={'user': 'videoag', 'password': 'asd', 'ref': '/'})
assert flask.session['user']
assert r.status_code == 403
assert 'Login fehlgeschlagen' in r.data.decode()
def test_logout(self):
with self.app as c:
with c.session_transaction() as sess:
sess['user'] = {'foo': 'bar'}
r = c.get('/internal/logout', data={'ref': '/'})
assert not flask.session.get('user')
assert r.status_code == 302
assert '<a href="/">' in r.data.decode()
def test_edit(self):
with self.app as c:
# test auth
r = c.get('/internal/new/courses', data={'title': 'Neue Vera14352345nstaltung totalyrandomcrap', 'responsible': 'foo', 'handle': '2r5sQ46z4w3DFCRT3<F4>DG', '_csrf_token': 'asd'})
assert r.status_code != 200
r = c.get('/internal/changelog')
assert r.status_code == 302
# all other tests are done logged in
self.login(c)
# add course
r = c.get('/internal/new/courses', data={'title': 'Neue Veranstaltung totalyrandomcrap', 'responsible': 'foo', 'handle': '2r5sQDFCRT3DG', '_csrf_token': 'asd'})
assert r.status_code == 200
r = self.app.get('/courses')
assert r.status_code == 200
assert 'Neue Veranstaltung totalyrandomcrap' in r.data.decode() and '2r5sQDFCRT3DG' in r.data.decode()
# rename lecture
r = c.get('internal/edit', data={"lectures.7353.title":"Testtitle","_csrf_token":"asd"})
assert r.status_code == 200
# test if the changelog is written
r = c.get('/internal/changelog')
assert r.status_code == 200
assert 'Testtitle' in r.data.decode() and 'lectures.7353.title' in r.data.decode()
def test_legacyurl(self):
with self.app as c:
r = self.app.get('/site/feed.php?newcourses')
assert r.status_code == 302
assert url_for('courses_feed') in r.data.decode()
r = self.app.get('/?view=faq')
assert r.status_code == 302
assert url_for('faq') in r.data.decode()
r = self.app.get('/site/feed.php?all')
assert r.status_code == 302
assert url_for('feed') in r.data.decode()
r = self.app.get('/?course=16ws-progra')
assert r.status_code == 302
assert url_for('course', handle='16ws-progra') in r.data.decode()
r = self.app.get('/?view=player&lectureid=7319')
assert r.status_code == 302
assert url_for('lecture', id='7319', course='16ws-progra') in r.data.decode()
r = self.app.get('/site/feed.php?16ws-afi')
assert r.status_code == 302
assert url_for('feed', handle='16ws-afi') in r.data.decode()
r = self.app.get('/site/feed.php?lecture=7319')
assert r.status_code == 302
assert False # missing
r = self.app.get('/site/feed.php?vid=6088')
assert r.status_code == 302
assert False # missing
if __name__ == '__main__':
unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment