diff --git a/jobs.py b/jobs.py
index 80ff34b821a0349adedb2f491e7e792a468d7c02..06ff730b78f65310f42c83bfd8b2ea0c791c531d 100644
--- a/jobs.py
+++ b/jobs.py
@@ -114,3 +114,11 @@ def jobs_schedule(hostname):
 				return 'no jobs', 503
 
 	return Response(json.dumps(job, default=date_json_handler), mimetype='application/json')
+
+@app.route('/internal/jobs/add/thumbnail', methods=['GET', 'POST'])
+@mod_required
+@csrf_protect
+@handle_errors('jobs_overview', 'Zu dieser Veranstaltung existieren keine Videos!', 404, IndexError)
+def add_thumbnail_job():
+	schedule_thumbnail(request.values['lectureid'])
+	return redirect(request.values.get('ref', url_for('jobs_overview')))
diff --git a/sorter.py b/sorter.py
index f48b0b4f2b08eca3599da991b0c2dcfb4cee869f..9811f855b2f4b539f42c23e9f502b7e6afbaa08a 100644
--- a/sorter.py
+++ b/sorter.py
@@ -39,14 +39,6 @@ def update_video_metadata(jobid, jobtype, data, state, status):
 	modify('UPDATE videos_data SET hash = ?, file_size = ?, duration = ? WHERE id = ?',
 			status['hash'], status['filesize'], status['duration'], data['video_id'])
 
-@app.route('/internal/jobs/add/thumbnail', methods=['GET', 'POST'])
-@mod_required
-@csrf_protect
-@handle_errors('jobs_overview', 'Zu dieser Veranstaltung existieren keine Videos!', 404, IndexError)
-def add_thumbnail_job():
-	schedule_thumbnail(request.values['lectureid'])
-	return redirect(request.values.get('ref', url_for('jobs_overview')))
-
 def insert_video(lectureid, dbfilepath, fileformatid, hash="", filesize=-1, duration=-1, sourceid=None):
 	visible = query('SELECT courses.autovisible FROM courses JOIN lectures ON lectures.course_id = courses.id WHERE lectures.id = ?', lectureid)[0]['autovisible']
 	video_id = modify('''INSERT INTO videos_data 
@@ -116,8 +108,10 @@ def filter_lectures_by_keywords(lectures, keywords):
 		for lecture in lectures:
 			for keyword in keywords:
 				# first test for exact match, else make it asci and try substring test
-				if (keyword == lecture[field]) or \
-					 (str(keyword).lower() in str(to_ascii(lecture[field]).lower())):
+				if (field in lecture) and (
+						(keyword == lecture[field]) or
+						(to_ascii(str(keyword).lower()) in str(to_ascii(lecture[field]).lower()))
+						):
 					return [lecture]
 	return []
 
diff --git a/tests/test_sorter.py b/tests/test_sorter.py
index 0a3c87884772c5ea798f9334290aaba00c2b46d6..2a8501f085d377407da1f29421a111281fdce5c4 100644
--- a/tests/test_sorter.py
+++ b/tests/test_sorter.py
@@ -19,7 +19,7 @@ class SorterTestCase(FlaskTestCase):
 			result = sorter.split_filename(test['filename'])
 			assert result == test['chunks'], 'result was {}, should be {}'.format(result, test)
 
-	def extract_format_keyword_from_filename(self):
+	def test_extract_format_keyword_from_filename(self):
 		testdata = [
 				{'chunks': ['',''], 'format': ''},
 				{'chunks': ['asd','720p'], 'format': '720p'},
@@ -56,10 +56,47 @@ class SorterTestCase(FlaskTestCase):
 			assert result == test['data'], 'result was {}, should be {}'.format(result, test['data'])
 
 	def test_filter_lectures_by_keywords(self):
-		pass
+		testdata = [
+				{'lectures': [], 'keywords': []},
+				{'lectures': [{'title': 'a', 'result': True}, {'title': 'b:', 'result': False}], 'keywords': ['a']},
+				{'lectures': [{'speaker': 'aca', 'result': True}, {'comment': 'bbd:', 'result': False}], 'keywords': ['c']},
+				{'lectures': [{'internal': 'apäöa', 'result': False}, {'comment': 'bbd:', 'result': False}], 'keywords': ['c']},
+				{'lectures': [{'internal': 'alll', 'result': False}, {'comment': 'bbdäo', 'result': True}], 'keywords': ['ä']},
+				]
+		for test in testdata:
+			result = sorter.filter_lectures_by_keywords(test['lectures'], test['keywords'])
+			for i in result:
+				assert i.get('result')
+			for i in test.get('lectures', []):
+				assert (not i.get('result')) or (i in result)
+
 	def test_filter_lectures_by_datetime(self):
+		testdata = [
+				{'lectures': [], 'date': None, 'time': None},
+				{'lectures': [{'time': datetime(year=2000, month=1, day=1), 'result': True}], 'date': None, 'time': time(hour=0, minute=0)},
+				{'lectures': [{'time': datetime(year=2000, month=1, day=1), 'result': False}], 'date': None, 'time': time(hour=0, minute=1)},
+				{'lectures': [{'result': False}], 'date': None, 'time': time(hour=0, minute=1)},
+				# TODO: add more testdata
+				]
+		for test in testdata:
+			result = sorter.filter_lectures_by_datetime(test['lectures'], test.get('date'), test.get('time'))
+			for i in result:
+				assert i.get('result')
+			for i in test.get('lectures', []):
+				assert (not i.get('result')) or (i in result)
 		pass
 	def test_filter_formats_by_filename(self):
 		pass
 	def test_sort_file(self):
-		pass
+		testdata = [
+				{'filename': '08ws-swt-081118.mp4', 'match': [104], 'fmt': 0},
+				{'filename': '15ss-zkk-extremale-codes-1080p.mp4', 'match': [6095], 'fmt': 4},
+				{'filename': '15ws-afi-151027-720p.mp4', 'match': [6326], 'fmt': 5},
+				]
+		with self.requestContext:
+			for test in testdata:
+				match, fmt = sorter.sort_file(test['filename'])
+				assert len(match) == len(test['match'])
+				for i in match:
+					assert i['id'] in test['match'], '{} is not supposed to match, only {} is'.format(i['id'], test['match'])
+				assert fmt == test['fmt'], 'format id {} is wronge, it is supposed to be {}'.format(fmt, test['fmt'])