From e2a5c38b549655a7765472de5cbe19ba17f2c4a7 Mon Sep 17 00:00:00 2001
From: Andreas <andreasv@fsmpi.rwth-aachen.de>
Date: Sat, 2 Dec 2017 21:22:37 +0100
Subject: [PATCH] added some unit tests

---
 .gitignore |  2 ++
 README.md  |  6 ++++++
 db.py      |  2 ++
 server.py  | 12 +++++++++++-
 tests.py   | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 78 insertions(+), 1 deletion(-)
 create mode 100755 tests.py

diff --git a/.gitignore b/.gitignore
index 2886e55..299c19d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,5 @@ nginx.log
 nginx.pid
 nginx.conf
 uwsgi.sock
+.coverage
+htmlcov/
diff --git a/README.md b/README.md
index 5089659..b8d5b45 100644
--- a/README.md
+++ b/README.md
@@ -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`
diff --git a/db.py b/db.py
index 04f7fe8..f64e6a3 100644
--- a/db.py
+++ b/db.py
@@ -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()
diff --git a/server.py b/server.py
index 0d68848..b13d02c 100644
--- a/server.py
+++ b/server.py
@@ -25,6 +25,16 @@ 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
 if config['DEBUG']:
 	app.jinja_env.auto_reload = True
 
@@ -338,7 +348,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:
diff --git a/tests.py b/tests.py
new file mode 100755
index 0000000..d0a7a69
--- /dev/null
+++ b/tests.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+
+import os
+import unittest
+import server
+
+import flask
+
+class VideoTestCase(unittest.TestCase):
+	@classmethod
+	def setUpClass(cls):
+		server.app.testing = True
+	
+	@classmethod
+	def tearDownClass(cls):
+		os.unlink(server.app.config['SQLITE_DB'])
+	
+	def setUp(self):
+		self.app = server.app.test_client()
+
+	def test_index(self):
+		r = self.app.get('/')
+		assert r.status_code == 200
+	
+	def test_courses(self):
+		r = self.app.get('/courses')
+		assert r.status_code == 200
+	
+	def test_faq(self):
+		r = self.app.get('/faq')
+		assert r.status_code == 200
+	
+	def test_sitemap(self):
+		r = self.app.get('/sitemap.xml')
+		assert r.status_code == 200
+	
+	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()
+
+
+if __name__ == '__main__':
+	unittest.main()
+
-- 
GitLab