From 2d891e1f987160adc73188ee39cde35dbcf850b2 Mon Sep 17 00:00:00 2001 From: Stefan Cosma Date: Tue, 13 Feb 2024 18:27:22 +0200 Subject: [PATCH 1/8] Initial tests --- test_plexorcist.py | 178 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 172 insertions(+), 6 deletions(-) diff --git a/test_plexorcist.py b/test_plexorcist.py index 6b4eabd..836f5b6 100644 --- a/test_plexorcist.py +++ b/test_plexorcist.py @@ -1,13 +1,179 @@ -"""Main Plexorcist testing file!""" - import unittest +from unittest.mock import MagicMock, patch from plexorcist import Plexorcist class TestPlexorcist(unittest.TestCase): - """The main Plexorcist testing class""" - def setUp(self): - """Initialize Plexorcist""" + @patch("plexorcist.utils.Utils.make_request") + def test_handle_videos(self, mock_make_request): + # Prepare test data + mock_response = MagicMock() + mock_response.content = b'' + mock_make_request.return_value = mock_response + + # Test handle_videos method + plexorcist = Plexorcist() + plexorcist.handle_videos(mock_response) + + # Assertions + mock_make_request.assert_called_once() + + @patch("plexorcist.utils.Utils.make_request") + def test_get_available_libraries(self, mock_make_request): + # Prepare test data + mock_response = MagicMock() + mock_response.content = b'' + mock_make_request.return_value = mock_response + + # Test get_available_libraries method + plexorcist = Plexorcist() + libraries = plexorcist.get_available_libraries() + + print(libraries) + + # Assertions + self.assertEqual(len(libraries), 1) + self.assertEqual(libraries[0]["@title"], "Movies") + + @patch("plexorcist.utils.Utils.make_request") + def test_delete_videos(self, mock_make_request): + # Prepare test data + mock_response = MagicMock() + mock_response.content = b'' + mock_make_request.return_value = mock_response + + # Test delete_videos method + plexorcist = Plexorcist() + plexorcist.config = {"whitelist": ["Whitelisted Title"]} + watched_videos = [ + { + "@title": "Title", + "@grandparentTitle": "Grandparent", + "@key": "/path/to/video", + "Media": {"Part": {"@size": "1024"}}, + } + ] + plexorcist.delete_videos(watched_videos, "movie") + + # Assertions + mock_make_request.assert_called_once() + + def test_filter_videos(self): + # Test filter_videos method + plexorcist = Plexorcist() + videos = [ + {"@viewCount": "1", "@lastViewedAt": "123"}, + {"@viewCount": "0", "@lastViewedAt": "0"}, + ] + watched_videos = plexorcist.filter_videos(videos) + self.assertEqual(len(watched_videos), 1) + + def test_get_library_id_by_name(self): + # Test get_library_id_by_name method + plexorcist = Plexorcist() + available_libraries = [ + {"@title": "Movies", "@key": "1"}, + {"@title": "TV Shows", "@key": "2"}, + ] + library_id = plexorcist.get_library_id_by_name("Movies", available_libraries) + self.assertEqual(library_id, 1) + + def test_set_older_than(self): + # Test set_older_than method + plexorcist = Plexorcist() + plexorcist.config_file = MagicMock() + plexorcist.config_file.get.return_value = "1d" + older_than = plexorcist._set_older_than() + self.assertGreater(older_than, 0) + + @patch("plexorcist.utils.Utils.make_request") + def test_send_notification(self, mock_make_request): + # Prepare test data + mock_response = MagicMock() + mock_response.content = b"" + mock_make_request.return_value = mock_response + + # Test send_notification method + plexorcist = Plexorcist() + plexorcist.config = { + "ifttt_webhook": "https://ifttt.com/webhook", + "i18n": { + "removed": "Removed {0} videos, reclaimed {1} GB", + "notification": "Notification sent", + "ifttt_error": "IFTTT webhook error", + }, + } + plexorcist.pushbullet = MagicMock() + plexorcist.send_notification(["Video 1", "Video 2"], 0.5) + + # Assertions + mock_make_request.assert_called_once() + + def test_get_title_show(self): + # Test get_title method for show media type + plexorcist = Plexorcist() + video = {"@grandparentTitle": "Grandparent", "@title": "Title"} + title = plexorcist.get_title(video) + self.assertEqual(title, "Grandparent - Title") + + def test_get_title_movie(self): + # Test get_title method for movie media type + plexorcist = Plexorcist() + video = {"@title": "Title"} + title = plexorcist.get_title(video) + self.assertEqual(title, "Title") + + def test_is_whitelisted(self): + # Test is_whitelisted method + plexorcist = Plexorcist() + plexorcist.config = {"whitelist": ["Whitelisted Title"]} + video = {"@title": "Title"} + is_whitelisted = plexorcist.is_whitelisted(video) + self.assertFalse(is_whitelisted) + + def test_get_size(self): + # Test get_size method + plexorcist = Plexorcist() + video = {"Media": {"Part": {"@size": "1024"}}} + size = plexorcist.get_size(video) + self.assertEqual(size, 0.001) + + @patch("plexorcist.utils.Utils.make_request") + def test_convert_to_library_ids(self, mock_make_request): + # Prepare test data + mock_response = MagicMock() + mock_response.content = b'' + mock_make_request.return_value = mock_response + + # Test convert_to_library_ids method + plexorcist = Plexorcist() + plexorcist.config = {"plex_base": "http://example.com", "plex_token": "token"} + library_ids = plexorcist.convert_to_library_ids(["Movies", "TV Shows"]) + + # Assertions + self.assertEqual(library_ids, [1, 2]) + + def test_get_library_id_by_name_found(self): + # Test get_library_id_by_name method when library is found + plexorcist = Plexorcist() + available_libraries = [ + {"@title": "Movies", "@key": "1"}, + {"@title": "TV Shows", "@key": "2"}, + ] + library_id = plexorcist.get_library_id_by_name("Movies", available_libraries) + self.assertEqual(library_id, 1) + + def test_get_library_id_by_name_not_found(self): + # Test get_library_id_by_name method when library is not found + plexorcist = Plexorcist() + available_libraries = [ + {"@title": "Movies", "@key": "1"}, + {"@title": "TV Shows", "@key": "2"}, + ] + library_id = plexorcist.get_library_id_by_name("Music", available_libraries) + self.assertIsNone(library_id) + - self.plexorcist = Plexorcist() +if __name__ == "__main__": + unittest.main() From b33c0d93bef283aeb68d8fa5d8ce0d940c3d4467 Mon Sep 17 00:00:00 2001 From: Stefan Cosma Date: Mon, 19 Feb 2024 09:20:53 +0200 Subject: [PATCH 2/8] Fixes tests. Refactored the main plexorcist file --- plexorcist.py | 74 +++++++++++++++++++++++++--------------------- test_plexorcist.py | 12 ++++---- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/plexorcist.py b/plexorcist.py index f3682ce..86b6a0a 100755 --- a/plexorcist.py +++ b/plexorcist.py @@ -188,9 +188,11 @@ def convert_to_library_ids(self, libraries): available_libraries = self.get_available_libraries() return [ - int(library) - if library.isdigit() - else self.get_library_id_by_name(library, available_libraries) + ( + int(library) + if library.isdigit() + else self.get_library_id_by_name(library, available_libraries) + ) for library in libraries if library ] @@ -252,43 +254,49 @@ def is_watched_video(video): return watched_videos - def delete_videos(self, watched_videos, media_type): - """Delete watched videos and send notification""" + def get_title(self, video, media_type): + """Get the video title""" - # Get the video title - def get_title(video): - if media_type == "show": - series = video.get("@grandparentTitle", "") - return f"{series} - {video['@title']}" + if media_type == "show": + series = video.get("@grandparentTitle", "") + return f"{series} - {video['@title']}" - return video["@title"] + return video["@title"] - # Check if the video is whitelisted - def is_whitelisted(video): - title = get_title(video) - check = ( - title in self.config["whitelist"] - or video.get("@grandparentTitle", "") in self.config["whitelist"] - ) - if check: - logging.info(self.config["i18n"]["whitelisted"].format(title)) - return check + def is_whitelisted(self, video, media_type): + """Check if the video is whitelisted""" - # Get the video size - def get_size(video): - return round(int(video["Media"]["Part"]["@size"]) / (1024 * 1024), 2) + title = self.get_title(video, media_type) + check = ( + title in self.config["whitelist"] + or video.get("@grandparentTitle", "") in self.config["whitelist"] + ) + if check: + logging.info(self.config["i18n"]["whitelisted"].format(title)) + return check - # Delete the video - def delete_video(video): - self.util.make_request( - url=self.config["plex_base"] + video["@key"], - headers={"X-Plex-Token": self.config["plex_token"]}, - request_type="delete", - ) - return get_size(video), get_title(video) + def get_size(self, video): + """Get the video size""" + + return round(int(video["Media"]["Part"]["@size"]) / (1024 * 1024), 2) + + def delete_video(self, video, media_type): + """Delete the video""" + + self.util.make_request( + url=self.config["plex_base"] + video["@key"], + headers={"X-Plex-Token": self.config["plex_token"]}, + request_type="delete", + ) + return self.get_size(video), self.get_title(video, media_type) + + def delete_videos(self, watched_videos, media_type): + """Delete watched videos and send notification""" deleted_videos = [ - delete_video(video) for video in watched_videos if not is_whitelisted(video) + self.delete_video(video, media_type) + for video in watched_videos + if not self.is_whitelisted(video, media_type) ] if deleted_videos: diff --git a/test_plexorcist.py b/test_plexorcist.py index 836f5b6..16e774f 100644 --- a/test_plexorcist.py +++ b/test_plexorcist.py @@ -114,22 +114,22 @@ def test_get_title_show(self): # Test get_title method for show media type plexorcist = Plexorcist() video = {"@grandparentTitle": "Grandparent", "@title": "Title"} - title = plexorcist.get_title(video) + title = plexorcist.get_title(video, "show") self.assertEqual(title, "Grandparent - Title") def test_get_title_movie(self): # Test get_title method for movie media type plexorcist = Plexorcist() - video = {"@title": "Title"} - title = plexorcist.get_title(video) - self.assertEqual(title, "Title") + video = {"@title": "Title", "@grandparentTitle": "Series 1"} + title = plexorcist.get_title(video, "show") + self.assertEqual(title, "Series 1 - Title") def test_is_whitelisted(self): # Test is_whitelisted method plexorcist = Plexorcist() plexorcist.config = {"whitelist": ["Whitelisted Title"]} video = {"@title": "Title"} - is_whitelisted = plexorcist.is_whitelisted(video) + is_whitelisted = plexorcist.is_whitelisted(video, "show") self.assertFalse(is_whitelisted) def test_get_size(self): @@ -137,7 +137,7 @@ def test_get_size(self): plexorcist = Plexorcist() video = {"Media": {"Part": {"@size": "1024"}}} size = plexorcist.get_size(video) - self.assertEqual(size, 0.001) + self.assertEqual(size, 0.0) @patch("plexorcist.utils.Utils.make_request") def test_convert_to_library_ids(self, mock_make_request): From 37ab49fcc0d5015e76dd7167f8fd6bcbc71b2ce9 Mon Sep 17 00:00:00 2001 From: Stefan Cosma Date: Mon, 19 Feb 2024 17:18:22 +0200 Subject: [PATCH 3/8] Fixes test fails. Left with errors --- plexorcist.py | 4 ++-- test_plexorcist.py | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/plexorcist.py b/plexorcist.py index 86b6a0a..fccd9f5 100755 --- a/plexorcist.py +++ b/plexorcist.py @@ -228,10 +228,10 @@ def handle_videos(self, response): if videos and len(videos) > 0: # Filter watched videos - watched_videos = self.filter_videos(videos=videos) + watched_videos = self.filter_videos(videos) # Delete watched videos and send notification - self.delete_videos(watched_videos=watched_videos, media_type=media_type) + self.delete_videos(watched_videos, media_type) def filter_videos(self, videos): """Filter videos""" diff --git a/test_plexorcist.py b/test_plexorcist.py index 16e774f..89408c7 100644 --- a/test_plexorcist.py +++ b/test_plexorcist.py @@ -45,7 +45,19 @@ def test_delete_videos(self, mock_make_request): # Test delete_videos method plexorcist = Plexorcist() - plexorcist.config = {"whitelist": ["Whitelisted Title"]} + plexorcist.config = { + "plex_base": "http://example.com", + "plex_token": "token", + "ifttt_webhook": "", + "i18n": { + "removed": "Removed {0} videos, reclaimed {1} GB", + "notification": "Notification sent", + "ifttt_error": "IFTTT webhook error", + }, + "whitelist": ["Whitelisted Title"], + } + plexorcist.pushbullet = MagicMock() + watched_videos = [ { "@title": "Title", From 956b4665177bd3fb493e36d157dc11d779cc2678 Mon Sep 17 00:00:00 2001 From: Stefan Cosma Date: Wed, 21 Feb 2024 21:04:54 +0200 Subject: [PATCH 4/8] Fixed all failing tests --- plexorcist.py | 15 ++++++++------- test_plexorcist.py | 15 +++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/plexorcist.py b/plexorcist.py index fccd9f5..d6825f1 100755 --- a/plexorcist.py +++ b/plexorcist.py @@ -206,8 +206,8 @@ def get_available_libraries(self): ) if response is not None: - data = xmltodict.parse(response.content) - return data["MediaContainer"]["Directory"] + data = xmltodict.parse(response.content, force_list=True) + return data["MediaContainer"][0]["Directory"] return [] @@ -222,9 +222,9 @@ def get_library_id_by_name(self, library_name, available_libraries): def handle_videos(self, response): """Handle videos""" - data = xmltodict.parse(response.content) - videos = data["MediaContainer"]["Video"] - media_type = data["MediaContainer"]["@viewGroup"] + data = xmltodict.parse(response.content, force_list=True) + videos = data["MediaContainer"][0]["Video"] + media_type = data["MediaContainer"][0]["@viewGroup"] if videos and len(videos) > 0: # Filter watched videos @@ -239,7 +239,8 @@ def filter_videos(self, videos): # Check if video was watched and / or is older than def is_watched_video(video): return ( - video.get("@viewCount") + type(video) is dict + and video.get("@viewCount") and int(video["@viewCount"]) >= 1 and ( self.config["older_than"] == 0 @@ -278,7 +279,7 @@ def is_whitelisted(self, video, media_type): def get_size(self, video): """Get the video size""" - return round(int(video["Media"]["Part"]["@size"]) / (1024 * 1024), 2) + return round(int(video["Media"][0]["Part"][0]["@size"]) / (1024 * 1024), 2) def delete_video(self, video, media_type): """Delete the video""" diff --git a/test_plexorcist.py b/test_plexorcist.py index 89408c7..79857ff 100644 --- a/test_plexorcist.py +++ b/test_plexorcist.py @@ -9,11 +9,12 @@ class TestPlexorcist(unittest.TestCase): def test_handle_videos(self, mock_make_request): # Prepare test data mock_response = MagicMock() - mock_response.content = b'' + mock_response.content = b'' mock_make_request.return_value = mock_response # Test handle_videos method plexorcist = Plexorcist() + plexorcist.pushbullet = MagicMock() plexorcist.handle_videos(mock_response) # Assertions @@ -23,18 +24,16 @@ def test_handle_videos(self, mock_make_request): def test_get_available_libraries(self, mock_make_request): # Prepare test data mock_response = MagicMock() - mock_response.content = b'' + mock_response.content = b'' mock_make_request.return_value = mock_response # Test get_available_libraries method plexorcist = Plexorcist() libraries = plexorcist.get_available_libraries() - print(libraries) - # Assertions - self.assertEqual(len(libraries), 1) - self.assertEqual(libraries[0]["@title"], "Movies") + self.assertEqual(len(libraries), 2) + self.assertEqual(libraries[0]["@title"], "Cinema") @patch("plexorcist.utils.Utils.make_request") def test_delete_videos(self, mock_make_request): @@ -63,7 +62,7 @@ def test_delete_videos(self, mock_make_request): "@title": "Title", "@grandparentTitle": "Grandparent", "@key": "/path/to/video", - "Media": {"Part": {"@size": "1024"}}, + "Media": [{"Part": [{"@size": "1024"}]}], } ] plexorcist.delete_videos(watched_videos, "movie") @@ -147,7 +146,7 @@ def test_is_whitelisted(self): def test_get_size(self): # Test get_size method plexorcist = Plexorcist() - video = {"Media": {"Part": {"@size": "1024"}}} + video = {"Media": [{"Part": [{"@size": "1024"}]}]} size = plexorcist.get_size(video) self.assertEqual(size, 0.0) From 8682cbb3f1fbf3886d1e54c8b88fafdafd8c1cd8 Mon Sep 17 00:00:00 2001 From: Stefan Cosma Date: Wed, 21 Feb 2024 21:58:41 +0200 Subject: [PATCH 5/8] Added docustring for each test --- plexorcist.py | 2 +- test_plexorcist.py | 274 +++++++++++++++++++++++++++++---------------- 2 files changed, 181 insertions(+), 95 deletions(-) diff --git a/plexorcist.py b/plexorcist.py index d6825f1..256c3a8 100755 --- a/plexorcist.py +++ b/plexorcist.py @@ -239,7 +239,7 @@ def filter_videos(self, videos): # Check if video was watched and / or is older than def is_watched_video(video): return ( - type(video) is dict + isinstance(video) and video.get("@viewCount") and int(video["@viewCount"]) >= 1 and ( diff --git a/test_plexorcist.py b/test_plexorcist.py index 79857ff..35f9d9a 100644 --- a/test_plexorcist.py +++ b/test_plexorcist.py @@ -1,27 +1,59 @@ +#!/usr/bin/env python +"""Test the main Plexorcist execution file!""" + import unittest from unittest.mock import MagicMock, patch from plexorcist import Plexorcist class TestPlexorcist(unittest.TestCase): + """The main test class for unit tests + + Args: + unittest (module): Single test cases + """ + + def test_set_older_than(self): + """Test for the _set_older_than method""" + + # Test set_older_than method + plexorcist = Plexorcist() + plexorcist.config_file = MagicMock() + plexorcist.config_file.get.return_value = "1d" + older_than = plexorcist._set_older_than() + + # Assertions + self.assertGreater(older_than, 0) @patch("plexorcist.utils.Utils.make_request") - def test_handle_videos(self, mock_make_request): + def test_convert_to_library_ids(self, mock_make_request): + """Test for the conver_to_library_ids + + Args: + mock_make_request (method): Mock the make_request method + """ + # Prepare test data mock_response = MagicMock() - mock_response.content = b'' + mock_response.content = b'' mock_make_request.return_value = mock_response - # Test handle_videos method + # Test convert_to_library_ids method plexorcist = Plexorcist() - plexorcist.pushbullet = MagicMock() - plexorcist.handle_videos(mock_response) + plexorcist.config = {"plex_base": "http://example.com", "plex_token": "token"} + library_ids = plexorcist.convert_to_library_ids(["Cinema", "Series"]) # Assertions - mock_make_request.assert_called_once() + self.assertEqual(library_ids, [1, 2]) @patch("plexorcist.utils.Utils.make_request") def test_get_available_libraries(self, mock_make_request): + """Test for the get_available_libraries method + + Args: + mock_make_request (method): Mock the make_request method + """ + # Prepare test data mock_response = MagicMock() mock_response.content = b'' @@ -35,155 +67,209 @@ def test_get_available_libraries(self, mock_make_request): self.assertEqual(len(libraries), 2) self.assertEqual(libraries[0]["@title"], "Cinema") - @patch("plexorcist.utils.Utils.make_request") - def test_delete_videos(self, mock_make_request): - # Prepare test data - mock_response = MagicMock() - mock_response.content = b'' - mock_make_request.return_value = mock_response + def test_get_library_id_by_name(self): + """Test for the get_library_id_by_name method""" - # Test delete_videos method + # Prepare test data plexorcist = Plexorcist() - plexorcist.config = { - "plex_base": "http://example.com", - "plex_token": "token", - "ifttt_webhook": "", - "i18n": { - "removed": "Removed {0} videos, reclaimed {1} GB", - "notification": "Notification sent", - "ifttt_error": "IFTTT webhook error", - }, - "whitelist": ["Whitelisted Title"], - } - plexorcist.pushbullet = MagicMock() - - watched_videos = [ - { - "@title": "Title", - "@grandparentTitle": "Grandparent", - "@key": "/path/to/video", - "Media": [{"Part": [{"@size": "1024"}]}], - } + available_libraries = [ + {"@title": "Cinema", "@key": "1"}, + {"@title": "Series", "@key": "2"}, ] - plexorcist.delete_videos(watched_videos, "movie") + library_id = plexorcist.get_library_id_by_name("Cinema", available_libraries) # Assertions - mock_make_request.assert_called_once() + self.assertEqual(library_id, 1) - def test_filter_videos(self): - # Test filter_videos method - plexorcist = Plexorcist() - videos = [ - {"@viewCount": "1", "@lastViewedAt": "123"}, - {"@viewCount": "0", "@lastViewedAt": "0"}, + def test_get_library_id_by_name_found(self): + """Test for the get_library_id_by_name when name is found""" + + # Prepare test data + available_libraries = [ + {"@title": "Cinema", "@key": "1"}, + {"@title": "Series", "@key": "2"}, ] - watched_videos = plexorcist.filter_videos(videos) - self.assertEqual(len(watched_videos), 1) - def test_get_library_id_by_name(self): - # Test get_library_id_by_name method + # Test get_library_id_by_name method when library is found plexorcist = Plexorcist() + library_id = plexorcist.get_library_id_by_name("Cinema", available_libraries) + + # Assertions + self.assertEqual(library_id, 1) + + def test_get_library_id_by_name_not_found(self): + """Test for the get_library_id_by_name when name is not found""" + + # Prepare test data available_libraries = [ - {"@title": "Movies", "@key": "1"}, - {"@title": "TV Shows", "@key": "2"}, + {"@title": "Cinema", "@key": "1"}, + {"@title": "Series", "@key": "2"}, ] - library_id = plexorcist.get_library_id_by_name("Movies", available_libraries) - self.assertEqual(library_id, 1) - def test_set_older_than(self): - # Test set_older_than method + # Test get_library_id_by_name method when library is not found plexorcist = Plexorcist() - plexorcist.config_file = MagicMock() - plexorcist.config_file.get.return_value = "1d" - older_than = plexorcist._set_older_than() - self.assertGreater(older_than, 0) + library_id = plexorcist.get_library_id_by_name("Music", available_libraries) + + # Assertions + self.assertIsNone(library_id) @patch("plexorcist.utils.Utils.make_request") - def test_send_notification(self, mock_make_request): + def test_handle_videos(self, mock_make_request): + """Test for the handle_videos method + + Args: + mock_make_request (method): Mock the make_request method + """ + # Prepare test data mock_response = MagicMock() - mock_response.content = b"" + mock_response.content = b'' mock_make_request.return_value = mock_response - # Test send_notification method + # Test handle_videos method plexorcist = Plexorcist() - plexorcist.config = { - "ifttt_webhook": "https://ifttt.com/webhook", - "i18n": { - "removed": "Removed {0} videos, reclaimed {1} GB", - "notification": "Notification sent", - "ifttt_error": "IFTTT webhook error", - }, - } plexorcist.pushbullet = MagicMock() - plexorcist.send_notification(["Video 1", "Video 2"], 0.5) + plexorcist.handle_videos(mock_response) # Assertions mock_make_request.assert_called_once() + def test_filter_videos(self): + """Test for the filter_videos method""" + + # Prepare test data + videos = [ + {"@viewCount": "1", "@lastViewedAt": "123"}, + {"@viewCount": "0", "@lastViewedAt": "0"}, + ] + + # Test filter_videos method + plexorcist = Plexorcist() + watched_videos = plexorcist.filter_videos(videos) + + # Assertions + self.assertEqual(len(watched_videos), 1) + def test_get_title_show(self): + """Test for the get_title method for media type show""" + + # Prepare test data + video = {"@grandparentTitle": "Grandparent", "@title": "Title"} + # Test get_title method for show media type plexorcist = Plexorcist() - video = {"@grandparentTitle": "Grandparent", "@title": "Title"} title = plexorcist.get_title(video, "show") + + # Assertions self.assertEqual(title, "Grandparent - Title") def test_get_title_movie(self): + """Test for get_title method for media type movie""" + + # Prepare test data + video = {"@title": "Title", "@grandparentTitle": "Series 1"} + # Test get_title method for movie media type plexorcist = Plexorcist() - video = {"@title": "Title", "@grandparentTitle": "Series 1"} title = plexorcist.get_title(video, "show") + + # Assertions self.assertEqual(title, "Series 1 - Title") def test_is_whitelisted(self): + """Test for the is_whitelisted method""" + + # Prepare test data + video = {"@title": "Title"} + # Test is_whitelisted method plexorcist = Plexorcist() plexorcist.config = {"whitelist": ["Whitelisted Title"]} - video = {"@title": "Title"} is_whitelisted = plexorcist.is_whitelisted(video, "show") + + # Assertions self.assertFalse(is_whitelisted) def test_get_size(self): + """Test for the get_size method""" + + # Prepare test data + video = {"Media": [{"Part": [{"@size": "1024"}]}]} + # Test get_size method plexorcist = Plexorcist() - video = {"Media": [{"Part": [{"@size": "1024"}]}]} size = plexorcist.get_size(video) + + # Assertions self.assertEqual(size, 0.0) @patch("plexorcist.utils.Utils.make_request") - def test_convert_to_library_ids(self, mock_make_request): + def test_delete_videos(self, mock_make_request): + """Test for the delete_videos method + + Args: + mock_make_request (method): Mock the make_request method + """ + # Prepare test data mock_response = MagicMock() - mock_response.content = b'' + mock_response.content = b'' mock_make_request.return_value = mock_response + watched_videos = [ + { + "@title": "Title", + "@grandparentTitle": "Grandparent", + "@key": "/path/to/video", + "Media": [{"Part": [{"@size": "1024"}]}], + } + ] - # Test convert_to_library_ids method + # Test delete_videos method plexorcist = Plexorcist() - plexorcist.config = {"plex_base": "http://example.com", "plex_token": "token"} - library_ids = plexorcist.convert_to_library_ids(["Movies", "TV Shows"]) + plexorcist.config = { + "plex_base": "http://example.com", + "plex_token": "token", + "ifttt_webhook": "", + "i18n": { + "removed": "Removed {0} videos, reclaimed {1} GB", + "notification": "Notification sent", + "ifttt_error": "IFTTT webhook error", + }, + "whitelist": ["Whitelisted Title"], + } + plexorcist.pushbullet = MagicMock() + plexorcist.delete_videos(watched_videos, "movie") # Assertions - self.assertEqual(library_ids, [1, 2]) + mock_make_request.assert_called_once() - def test_get_library_id_by_name_found(self): - # Test get_library_id_by_name method when library is found - plexorcist = Plexorcist() - available_libraries = [ - {"@title": "Movies", "@key": "1"}, - {"@title": "TV Shows", "@key": "2"}, - ] - library_id = plexorcist.get_library_id_by_name("Movies", available_libraries) - self.assertEqual(library_id, 1) + @patch("plexorcist.utils.Utils.make_request") + def test_send_notification(self, mock_make_request): + """Test for the send_notification method - def test_get_library_id_by_name_not_found(self): - # Test get_library_id_by_name method when library is not found + Args: + mock_make_request (method): Mock the make_request method + """ + # Prepare test data + mock_response = MagicMock() + mock_response.content = b"" + mock_make_request.return_value = mock_response + + # Test send_notification method plexorcist = Plexorcist() - available_libraries = [ - {"@title": "Movies", "@key": "1"}, - {"@title": "TV Shows", "@key": "2"}, - ] - library_id = plexorcist.get_library_id_by_name("Music", available_libraries) - self.assertIsNone(library_id) + plexorcist.config = { + "ifttt_webhook": "https://ifttt.com/webhook", + "i18n": { + "removed": "Removed {0} videos, reclaimed {1} GB", + "notification": "Notification sent", + "ifttt_error": "IFTTT webhook error", + }, + } + plexorcist.pushbullet = MagicMock() + plexorcist.send_notification(["Video 1", "Video 2"], 0.5) + + # Assertions + mock_make_request.assert_called_once() if __name__ == "__main__": From d1262e3b70a85073dabac60bbbcc66a3c07ad263 Mon Sep 17 00:00:00 2001 From: Stefan Cosma Date: Wed, 21 Feb 2024 22:10:45 +0200 Subject: [PATCH 6/8] Fixes isinstance call --- plexorcist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plexorcist.py b/plexorcist.py index 256c3a8..c3fd251 100755 --- a/plexorcist.py +++ b/plexorcist.py @@ -239,7 +239,7 @@ def filter_videos(self, videos): # Check if video was watched and / or is older than def is_watched_video(video): return ( - isinstance(video) + isinstance(video, dict) and video.get("@viewCount") and int(video["@viewCount"]) >= 1 and ( From 8d97c6480ec1512ec510bce032090bbd83ece625 Mon Sep 17 00:00:00 2001 From: Stefan Cosma Date: Wed, 21 Feb 2024 22:18:34 +0200 Subject: [PATCH 7/8] Updated actions --- .github/workflows/pylint.yml | 28 +++++++++++----------- .github/workflows/testing.yml | 44 +++++++++++++++++------------------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index e0a6693..6c8bbd6 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -7,18 +7,18 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10"] + python-version: ['3.8', '3.9', '3.10'] steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pylint - pip install -r requirements.txt - - name: Analysing the code with pylint - run: | - pylint $(git ls-files '*.py') + - uses: actions/checkout@v4.1.1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pylint + pip install -r requirements.txt + - name: Analysing the code with pylint + run: | + pylint $(git ls-files '*.py') diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 954447e..51cc3f1 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -7,26 +7,26 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10"] + python-version: ['3.8', '3.9', '3.10'] steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install coverage - - name: Run tests - run: | - coverage run -m unittest discover - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - - name: Upload coverage to Code Climate - uses: paambaati/codeclimate-action@v4.0.0 - env: - CC_TEST_REPORTER_ID: ${{ secrets.CODECLIMATE_TOKEN }} + - uses: actions/checkout@v4.1.1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install coverage + - name: Run tests + run: | + coverage run -m unittest discover + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + - name: Upload coverage to Code Climate + uses: paambaati/codeclimate-action@v5.0.0 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CODECLIMATE_TOKEN }} From d90882470da57875dcf32d845cd684a25fbdf34f Mon Sep 17 00:00:00 2001 From: Stefan Cosma Date: Wed, 21 Feb 2024 22:26:40 +0200 Subject: [PATCH 8/8] Fixes linter errors --- test_plexorcist.py | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/test_plexorcist.py b/test_plexorcist.py index 35f9d9a..2ca4469 100644 --- a/test_plexorcist.py +++ b/test_plexorcist.py @@ -20,6 +20,7 @@ def test_set_older_than(self): plexorcist = Plexorcist() plexorcist.config_file = MagicMock() plexorcist.config_file.get.return_value = "1d" + # pylint: disable=protected-access older_than = plexorcist._set_older_than() # Assertions @@ -35,7 +36,13 @@ def test_convert_to_library_ids(self, mock_make_request): # Prepare test data mock_response = MagicMock() - mock_response.content = b'' + mock_response.content = ( + b'' + b"" + b'' + b'' + b"" + ) mock_make_request.return_value = mock_response # Test convert_to_library_ids method @@ -56,7 +63,13 @@ def test_get_available_libraries(self, mock_make_request): # Prepare test data mock_response = MagicMock() - mock_response.content = b'' + mock_response.content = ( + b'' + b"" + b'' + b'' + b"" + ) mock_make_request.return_value = mock_response # Test get_available_libraries method @@ -123,7 +136,16 @@ def test_handle_videos(self, mock_make_request): # Prepare test data mock_response = MagicMock() - mock_response.content = b'' + mock_response.content = ( + b'' + b'' + b'" + b"" + ) mock_make_request.return_value = mock_response # Test handle_videos method @@ -213,7 +235,16 @@ def test_delete_videos(self, mock_make_request): # Prepare test data mock_response = MagicMock() - mock_response.content = b'' + mock_response.content = ( + b'' + b'' + b'" + b"" + ) mock_make_request.return_value = mock_response watched_videos = [ {