From d646043564f3bb30f9de81094d2acf1606282ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20K=C3=BCnzel?= <simonk@fsmpi.rwth-aachen.de> Date: Tue, 14 May 2024 23:16:04 +0200 Subject: [PATCH] More tests to cover most sql statements --- db_example.sql | 2 + encoding.py | 1 + feeds.py | 1 + importer.py | 3 + jobmanagement.py | 1 + livestreams.py | 9 +++ server.py | 4 ++ sorter.py | 2 + tests/test_misc.py | 167 ++++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 189 insertions(+), 1 deletion(-) diff --git a/db_example.sql b/db_example.sql index 3c1c2fa..b520677 100644 --- a/db_example.sql +++ b/db_example.sql @@ -8611,6 +8611,7 @@ INSERT INTO `videos_data` (`id`,`lecture_id`,`visible`,`deleted`,`downloadable`, INSERT INTO `videos_data` (`id`,`lecture_id`,`visible`,`deleted`,`downloadable`,`title`,`comment`,`internal`,`path`,`file_modified`,`time_created`,`time_updated`,`created_by`,`file_size`,`video_format`,`hash`) VALUES (9681,7012,1,0,1,'','','','pub/16ss-dsal/16ss-dsal-160715-1080p_1.mp4','2016-08-07 22:54:46','2016-08-07 21:02:37','2016-08-07 21:02:43',46,1402602183,4,'e036f7cbd51afd3ab7be10cf77747c00'); INSERT INTO `videos_data` (`id`,`lecture_id`,`visible`,`deleted`,`downloadable`,`title`,`comment`,`internal`,`path`,`file_modified`,`time_created`,`time_updated`,`created_by`,`file_size`,`video_format`,`hash`) VALUES (9682,7012,1,0,1,'','','','pub/16ss-dsal/16ss-dsal-160715-360p_1.mp4','2016-08-07 22:45:34','2016-08-07 21:02:38','2016-08-07 21:02:45',46,368611109,10,'fae2bda2da55a3005aa6329a2d0227c3'); INSERT INTO `videos_data` (`id`,`lecture_id`,`visible`,`deleted`,`downloadable`,`title`,`comment`,`internal`,`path`,`file_modified`,`time_created`,`time_updated`,`created_by`,`file_size`,`video_format`,`hash`) VALUES (9683,7012,1,0,1,'','','','pub/16ss-dsal/16ss-dsal-160715-720p_1.mp4','2016-08-07 22:46:00','2016-08-07 21:02:40','2016-08-07 21:02:44',46,721141077,5,'083c0b7693c82078c513707d1402096b'); +INSERT INTO `videos_data` (`id`,`lecture_id`,`visible`,`deleted`,`downloadable`,`title`,`comment`,`internal`,`path`,`file_modified`,`time_created`,`time_updated`,`created_by`,`file_size`,`video_format`,`hash`, `source`) VALUES (16080,7012,1,0,1,'','','','pub/17ws-cgbp/17ws-cgbp-171114-720p.mp4','2018-01-12 04:36:44','2018-01-12 04:36:44','2018-01-12 04:36:44',-1,607257928,5,"8fa956b14162ec42c1dabc11d53671c5",89); INSERT INTO `users` (`id`,`name`,`realname`,`level`,`fsacc`,`last_login`,`calendar_key`,`rfc6238`) VALUES (1,'gustav1','Gustav Geier',0,'',NULL,'',''); INSERT INTO `users` (`id`,`name`,`realname`,`level`,`fsacc`,`last_login`,`calendar_key`,`rfc6238`) VALUES (2,'gustav2','Gustav Geier',0,'',NULL,'',''); INSERT INTO `users` (`id`,`name`,`realname`,`level`,`fsacc`,`last_login`,`calendar_key`,`rfc6238`) VALUES (4,'gustav4','Gustav Geier',0,'',NULL,'',''); @@ -14646,4 +14647,5 @@ INSERT INTO `areas` (`area`,`abbreviation`,`default`,`rank`,`coordinates`) VALUE INSERT INTO `profiles` (`name`,`format`) VALUES ('default',4); INSERT INTO `profiles` (`name`,`format`) VALUES ('default',5); INSERT INTO `profiles` (`name`,`format`) VALUES ('default',10); +INSERT INTO `sources` (`id`, `lecture_id`, `path`, `type`, `hash`, `time_created`) VALUES (89, 7012, 'autoencode/something', 'plain', '000000000', '2024-01-01 00:00:00'); COMMIT; diff --git a/encoding.py b/encoding.py index a4dc849..de8549e 100644 --- a/encoding.py +++ b/encoding.py @@ -117,6 +117,7 @@ def add_reencode_job(): @job_handler('probe-raw', 'intro') def update_lecture_videos(jobid, jobtype, data, state, status): #pylint: disable=unused-argument + # info: sql no test cover if 'lecture_id' not in data: return if jobtype == 'probe-raw': diff --git a/feeds.py b/feeds.py index cf4a548..4f4685c 100644 --- a/feeds.py +++ b/feeds.py @@ -52,6 +52,7 @@ def rss_feed(handle): GROUP BY formats.id ORDER BY formats.player_prio DESC''', course['id']) if not formats: + # info: sql no test cover formats = query('SELECT * FROM formats WHERE id = 4 OR id = 5 OR id = 10') # 360p, 720p, 1080p if 'format_id' not in request.values: return redirect(url_for('rss_feed', handle=handle, format_id=formats[0]['id'])) diff --git a/importer.py b/importer.py index 7cf3e02..90a5a6e 100644 --- a/importer.py +++ b/importer.py @@ -21,6 +21,7 @@ def list_import_sources(id): modify('INSERT INTO import_campus (url, type, course_id, last_checked, changed) VALUES (?, ?, ?, ?, 1)', campus[i]['url'], campus[i]['type'], id, datetime.now()) else: + # info: sql no test cover if campus[i]['url'] != '': query('UPDATE import_campus SET url = ?, "type" = ? WHERE (course_id = ?) AND (id = ?)', campus[i]['url'], campus[i]['type'], id, int(i)) else: @@ -99,6 +100,7 @@ def fetch_co_course_events(i): e['duration'] = int((datetime.strptime("%s %s"%(k, j['end']), fmt) - e['time']).seconds/60) j['place'] = str(j['place']) if j['place'] != '': + # info: sql no test cover dbplace = query("SELECT name FROM places WHERE (campus_room = ?) OR (campus_name = ?) OR ((NOT campus_name) AND name = ?)", j['place'], j['place'], j['place']) if dbplace: @@ -158,6 +160,7 @@ def fetch_ro_course_events(item): place = str(comp.get('LOCATION', '')) if place: campus_room = place.split('(')[-1].split(')')[0] + # info: sql no test cover dbplace = query('SELECT name FROM places WHERE campus_room = ?', campus_room) if dbplace: event['place'] = dbplace[0]['name'] diff --git a/jobmanagement.py b/jobmanagement.py index 8f84ce5..eca41b0 100644 --- a/jobmanagement.py +++ b/jobmanagement.py @@ -58,6 +58,7 @@ def cancel_job(job_id): query('UPDATE jobs SET canceled = true WHERE id = ?', job_id) def restart_job(job_id, canceled=False): + # info: sql no test cover if canceled: query('UPDATE jobs SET state = \'ready\', canceled = false WHERE id = ? AND state = \'failed\'', job_id) else: diff --git a/livestreams.py b/livestreams.py index dcb0e30..a68388a 100644 --- a/livestreams.py +++ b/livestreams.py @@ -45,6 +45,7 @@ def streamauth_legacy(server=None): if 'lecture' in request.values: match = {'id': request.values['lecture']} if not query("SELECT handle FROM streams WHERE handle = ?", request.values['name']): + # info: sql no test cover modify("INSERT INTO streams (handle, active, visible, lecture_id, description, poster) VALUES (?, false, true, -1, '', '')", request.values['name']) if server: data = {'src': 'rtmp://%s/live/%s'%(server, request.values['name']), @@ -53,6 +54,7 @@ def streamauth_legacy(server=None): modify("UPDATE streams SET active = true, lecture_id = ?, job_id = ? WHERE handle = ?", match['id'], job_id, request.values['name']) else: + # info: sql no test cover modify("UPDATE streams SET active = true, lecture_id = ? WHERE handle = ?", match['id'], request.values['name']) elif request.values['call'] == 'publish_done': @@ -103,6 +105,7 @@ def gentoken(): @app.route('/internal/streaming/rekey/<int:id>') @mod_required def streamrekey(id): + # info: sql no test cover modify('UPDATE live_sources SET "key" = ? WHERE id = ? AND NOT deleted', gentoken(), id) source = query('SELECT * FROM live_sources WHERE NOT deleted AND id = ?', id)[0] flash('''Der Streamkey von <strong>{name}</strong> wurde neu generiert: @@ -120,6 +123,7 @@ def streamrekey(id): @app.route('/internal/streaming/drop/<int:id>') @mod_required def streamdrop(id): + # info: sql no test cover source = (query('SELECT * FROM live_sources WHERE NOT deleted AND id = ?', id) or [None])[0] if not source: if 'ref' in request.values: @@ -134,6 +138,7 @@ def streamdrop(id): @sched_func(120) def live_source_thumbnail(): + # info: sql no test cover sources = query('SELECT * FROM live_sources WHERE clientid IS NOT NULL') for source in sources: schedule_job('thumbnail', {'srcurl': 'rtmp://%s/src/%i'%(source['server'], source['id']), 'filename': 's_%i.jpg'%source['id']}) @@ -146,6 +151,7 @@ def ip_in_networks(ip, networks): @app.route('/internal/streaming/auth/<server>', methods=['GET', 'POST']) def streamauth(server): + # info: sql no test cover # pylint: disable=too-many-return-statements if not ip_in_networks(request.headers['X-Real-IP'], config.get('FSMPI_IP_RANGES', [])): return 'Forbidden', 403 @@ -185,6 +191,7 @@ def streamauth(server): return 'Bad request', 400 def schedule_livestream(lecture_id): + # info: sql no test cover # pylint: disable=too-many-branches,too-many-statements lecture = query('SELECT * FROM lectures WHERE id = ?', lecture_id)[0] settings = json.loads(lecture['stream_settings']) @@ -294,6 +301,7 @@ def restart_failed_complex_live_transcode(id, type, data, state, status): # pyli @job_handler('complex_live_transcode', state='failed') @job_handler('complex_live_transcode', state='finished') def cleanup_after_complex_live_transcode_ended(id, type, data, state, status): # pylint: disable=unused-argument + # info: sql no test cover job = query('SELECT * FROM jobs WHERE id = ?', id, nlfix=False)[0] if state == 'finished' or (state == 'failed' and job['canceled']): modify('UPDATE lectures_data SET stream_job = NULL WHERE stream_job = ?', id) @@ -301,6 +309,7 @@ def cleanup_after_complex_live_transcode_ended(id, type, data, state, status): # @app.route('/internal/streaming/control', methods=['POST']) @mod_required def control_stream(): + # info: sql no test cover action = request.values['action'] lecture_id = int(request.values['lecture_id']) course = (query('SELECT courses.* FROM courses JOIN lectures ON (courses.id = lectures.course_id) WHERE lectures.id = ?', lecture_id) or [None])[0] diff --git a/server.py b/server.py index 2a3eda8..7036de5 100644 --- a/server.py +++ b/server.py @@ -33,6 +33,7 @@ if sys.argv[0].endswith('run_tests.py'): config['DEBUG'] = True config['DISABLE_SCHEDULER'] = True config['JOBS_API_KEY'] = '1' + config['SORTER_API_KEY'] = '1' if config['DEBUG']: app.jinja_env.auto_reload = True @@ -205,9 +206,11 @@ def index(): if item['type'] == 'courses': if item['param'] not in ['title', 'semester', 'organizer', 'subject']: continue + # info: sql no test cover item['courses'] = query('SELECT * FROM courses WHERE (visible AND listed) AND "%s" = ? ORDER BY "%s"'%(item['param'], item['param']), item['param2']) elif item['type'] == 'video': item['lecture'] = {'id': item['param']} + # info: sql no test cover streams = query('''SELECT streams.handle AS livehandle, streams.lecture_id, \'formats\' AS sep, formats.* FROM streams JOIN lectures ON lectures.id = streams.lecture_id @@ -526,6 +529,7 @@ def login(): session['user'] = userinfo dbuser = query('SELECT * FROM users WHERE name = ?', user) if not dbuser: + # info: sql no test cover modify('INSERT INTO users (name, realname, fsacc, level, calendar_key, rfc6238) VALUES (?, ?, ?, 1, \'\', \'\')', user, session['user']['givenName'], user) dbuser = query('SELECT * FROM users WHERE name = ?', user) session['user']['dbid'] = dbuser[0]['id'] diff --git a/sorter.py b/sorter.py index 258b242..b78017e 100644 --- a/sorter.py +++ b/sorter.py @@ -29,6 +29,7 @@ def to_ascii(inputstring): @job_handler('probe', 'remux', 'transcode') def update_video_metadata(jobid, jobtype, data, state, status): #pylint: disable=unused-argument + # info: sql no test cover if 'video_id' not in data: return if jobtype not in ['remux', 'transcode']: @@ -56,6 +57,7 @@ def add_thumbnail_job(): return redirect(request.values.get('ref', url_for('jobs_overview'))) def insert_video(lectureid, dbfilepath, fileformatid, hash="", filesize=-1, duration=-1, sourceid=None): #pylint: disable=too-many-arguments + # info: sql no test cover 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 (lecture_id, visible, path, video_format, title, comment, internal, file_modified, time_created, time_updated, created_by, hash, file_size, duration, source) diff --git a/tests/test_misc.py b/tests/test_misc.py index c98d47d..5e1ec64 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -60,6 +60,12 @@ class VideoTestCase(unittest.TestCase): assert r.status_code == 200 r = c.get('/15ws-einfprog') assert r.status_code == 200 + + r = c.get('/99') + assert r.status_code == 200 + + r = c.post('/99/2330/login', data={"username": "wrong", "password": "auth"}) + assert r.status_code == 302 def test_timetable(self): with self.app as c: @@ -175,6 +181,12 @@ class VideoTestCase(unittest.TestCase): r = c.get('/internal/changelog') assert r.status_code == 200 assert 'Testtitle' in r.data.decode() and 'lectures.7353.title' in r.data.decode() + + r = c.post('/internal/set/responsible/20/1', data={'_csrf_token': 'asd'}) + assert r.status_code == 200 + + r = c.post('/internal/unset/responsible/20/1', data={'_csrf_token': 'asd'}) + assert r.status_code == 200 def test_legacyurl(self): @@ -258,8 +270,24 @@ class VideoTestCase(unittest.TestCase): match, fmt = sorter.sort_file('15ss-zkk-extremale-codes-1080p.mp4') assert len(match) == 1 assert match[0]['id'] == 6095 + + self.login(c) + r = self.app.get('/internal/sort/log') + assert r.status_code == 200 + + r = self.app.post('/internal/jobs/add/thumbnail', data={'lectureid': 10, '_csrf_token': 'asd'}) + assert r.status_code == 302 + + r = self.app.get('/internal/sort/now') + assert r.status_code == 200 + + r = self.app.get('/internal/sort/encoded/something-wrong', data={'apikey': '1'}) + assert r.status_code == 400 + + r = self.app.get('/internal/sort/encoded/09ss-dsal-090619-720p.mp4', data={'apikey': '1'}) + assert r.status_code == 200 -# @unittest.skip("too slow") + @unittest.skip("too slow") def test_campusimport(self): with self.app as c: self.login(c) @@ -275,3 +303,140 @@ class VideoTestCase(unittest.TestCase): self.login(c) r = self.app.get('/internal/cutprogress') assert r.status_code == 200 + + # Some quick tests below to execute more sql statements + + def test_encoding(self): + with self.app as c: + self.login(c) + r = self.app.post('/internal/jobs/add/remux', data={'videoid': 28, '_csrf_token': 'asd'}) + assert r.status_code == 302 + + r = self.app.post('/internal/jobs/add/reencode', data={'videoid': 16080, '_csrf_token': 'asd'}) + assert r.status_code == 302 + + # Trigger edit handler + r = c.get('internal/edit', data={"courses.3.title":"Test","_csrf_token":"asd"}) + assert r.status_code == 200 + + def test_feeds(self): + with self.app as c: + r = self.app.get('/feed') + assert r.status_code == 200 + + r = self.app.get('/07ws-buk/feed') + assert r.status_code == 200 + + r = self.app.get('/07ws-buk/rss', data={'format_id':10}) + assert r.status_code == 200 + + r = self.app.get('/courses/feed') + assert r.status_code == 200 + + def test_icalexport(self): + with self.app as c: + self.login(c) + r = self.app.get('/internal/ical/user/1') + assert r.status_code == 200 + + r = self.app.get('/internal/ical/notuser/1') + assert r.status_code == 200 + + r = self.app.get('/internal/ical/course/1') + assert r.status_code == 200 + + def test_jobs(self): + with self.app as c: + self.login(c) + r = self.app.get('/internal/jobs/overview') + assert r.status_code == 200 + + r = self.app.get('/internal/jobs/overview?worker=worker0') + assert r.status_code == 200 + + r = self.app.post('/internal/jobs/action/clear_failed', data={'_csrf_token': 'asd'}) + assert r.status_code == 302 + + r = self.app.post('/internal/jobs/action/clear_failed/1', data={'_csrf_token': 'asd'}) + assert r.status_code == 302 + + r = self.app.post('/internal/jobs/action/retry_failed', data={'_csrf_token': 'asd'}) + assert r.status_code == 302 + + r = self.app.post('/internal/jobs/action/retry_failed/1', data={'_csrf_token': 'asd'}) + assert r.status_code == 302 + + r = self.app.post('/internal/jobs/action/copy/1', data={'_csrf_token': 'asd'}) + assert r.status_code == 302 + + r = self.app.post('/internal/jobs/action/delete/1', data={'_csrf_token': 'asd'}) + assert r.status_code == 302 + + r = self.app.post('/internal/jobs/action/cancel/1', data={'_csrf_token': 'asd'}) + assert r.status_code == 302 + + r = self.app.post('/internal/jobs/api/job/1/ping', data={'apikey': '1', 'host': 'test', 'status': '{}', 'state': 'finished'}) + assert r.status_code == 205 + + # Test new worker + import uuid + r = self.app.post(f'/internal/jobs/api/worker/{uuid.uuid4()}/schedule', data=json.dumps({'jobtypes': ['probe'], 'queues': ['default'], 'apikey': '1'}), content_type='application/json') + assert r.status_code in [200, 503] + + def test_auth(self): + with self.app as c: + r = self.app.get('/internal/auth', headers={'X-Original-Uri': 'https://videoag.fsmpi.rwth-aachen.de/files/pub/15ws-afi/15ws-afi-151022-720p.mp4'}) + assert r.status_code == 200 + + # Not found, but sql is executed + r = self.app.get('/internal/auth', headers={'X-Original-Uri': 'https://videoag.fsmpi.rwth-aachen.de/files/pub/hls/something'}) + assert r.status_code == 404 + + r = self.app.get('/internal/auth', headers={'X-Original-Uri': 'https://videoag.fsmpi.rwth-aachen.de/files/pub/hls/42'}) + assert r.status_code == 404 + + def test_stats(self): + with self.app as c: + self.login(c) + + r = self.app.get('/internal/stats') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/generic/formats_views') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/generic/course_count') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/generic/lectures_count') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/generic/categories_courses') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/generic/organizer_courses') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/generic/categories_lectures') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/generic/lecture_views') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/generic/live_views') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/generic/lecture_totalviews') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/viewsperday/lecture/1') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/viewsperday/course/1') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/viewsperday/global') + assert r.status_code == 200 + + r = self.app.get('/internal/stats/viewsperday/courses') + assert r.status_code == 200 -- GitLab