diff --git a/.github/workflows/build-test-lint.yaml b/.github/workflows/build-test-lint.yaml index e92f83f..5725699 100644 --- a/.github/workflows/build-test-lint.yaml +++ b/.github/workflows/build-test-lint.yaml @@ -52,7 +52,7 @@ jobs: #---------------------------------------------- - name: Test with pytest run: | - pytest --cov=src --cov-report=xml tests + pytest --cov-branch --cov=src --cov-report=xml tests #---------------------------------------------- # lint and formatting diff --git a/src/series_scanner.py b/src/series_scanner.py index 31591da..db57f3b 100644 --- a/src/series_scanner.py +++ b/src/series_scanner.py @@ -88,7 +88,7 @@ def __is_episode_airing_soon(self, episode_air_date_utc): episode_air_date_utc - datetime.now(timezone.utc) ).total_seconds() / 3600 - return hours_till_airing <= self.hours_before_air + return 0 < hours_till_airing <= self.hours_before_air def __has_episode_already_aired(self, episode_air_date_utc): """ diff --git a/tests/test_series_scanner.py b/tests/test_series_scanner.py index b5fc3ee..6a3cd81 100644 --- a/tests/test_series_scanner.py +++ b/tests/test_series_scanner.py @@ -1,8 +1,10 @@ import logging +from datetime import datetime, timedelta, timezone from typing import List import pytest from pycliarr.api import SonarrCli, SonarrSerieItem +from pycliarr.api.base_api import json_data from series_scanner import SeriesScanner @@ -14,19 +16,15 @@ def get_serie(self, mocker) -> None: ] mocker.patch.object(SonarrCli, "get_serie").return_value = series - @pytest.fixture - def get_ended_serie(self, mocker) -> None: - series: List[SonarrSerieItem] = [ - SonarrSerieItem(id=1, title="test title", status="ended") - ] - mocker.patch.object(SonarrCli, "get_serie").return_value = series - - @pytest.fixture - def get_episode(self, mocker) -> None: - series: List[SonarrSerieItem] = [ - SonarrSerieItem(id=1, title="test title", status="continuing") - ] - mocker.patch.object(SonarrCli, "get_serie").return_value = series + def episode_data( + self, id: int, title: str, airDateDelta: timedelta, seasonNumber: str + ) -> dict: + return dict( + id=id, + title=title, + airDateUtc=(datetime.now(timezone.utc) + airDateDelta).isoformat(), + seasonNumber=seasonNumber, + ) def test_no_series_returned(self, caplog, mocker) -> None: mocker.patch.object(SonarrCli, "get_serie").return_value = [] @@ -42,9 +40,11 @@ def test_when_series_returned_no_episodes(self, get_serie, caplog, mocker) -> No assert "Retrieved series list" in caplog.text assert "Error fetching episode list" in caplog.text - def test_when_show_status_not_continuuing( - self, get_ended_serie, caplog, mocker - ) -> None: + def test_when_show_status_not_continuuing(self, caplog, mocker) -> None: + series: List[SonarrSerieItem] = [ + SonarrSerieItem(id=1, title="test title", status="ended") + ] + mocker.patch.object(SonarrCli, "get_serie").return_value = series get_episode = mocker.patch.object(SonarrCli, "get_episode") get_episode.return_value = [] @@ -66,6 +66,84 @@ def test_when_multiple_shows_continuing_and_ended(self, caplog, mocker) -> None: with caplog.at_level(logging.DEBUG): SeriesScanner("test", "test.tld", "test-api-key", 4).scan() - # assert "Error fetching episode list" in caplog.text get_episode.assert_called_once_with(1) + + def test_when_episodes_filtered_out(self, get_serie, caplog, mocker) -> None: + episodes: List[json_data] = [ + self.episode_data( + id=1, + title="TBA", + airDateDelta=timedelta(hours=8), + seasonNumber=1, + ), + self.episode_data( + id=2, + title="title", + airDateDelta=timedelta(hours=-2), + seasonNumber=1, + ), + self.episode_data( + id=3, + title="TBA", + airDateDelta=timedelta(hours=2), + seasonNumber=0, + ), + dict( + id=4, + title="TBA", + airDateUtc=None, + seasonNumber=1, + ), + ] + mocker.patch.object(SonarrCli, "get_episode").return_value = episodes + + refresh_serie = mocker.patch.object(SonarrCli, "refresh_serie") + + with caplog.at_level(logging.DEBUG): + SeriesScanner("test", "test.tld", "test-api-key", 4).scan() + + assert "Retrieved episode list" in caplog.text + assert not refresh_serie.called + + def test_when_tba_episode_is_airing_soon(self, get_serie, caplog, mocker) -> None: + episodes: List[json_data] = [ + self.episode_data( + id=1, + title="TBA", + airDateDelta=timedelta(hours=2), + seasonNumber=1, + ) + ] + mocker.patch.object(SonarrCli, "get_episode").return_value = episodes + + refresh_serie = mocker.patch.object(SonarrCli, "refresh_serie") + + with caplog.at_level(logging.DEBUG): + SeriesScanner("test", "test.tld", "test-api-key", 4).scan() + + assert refresh_serie.called + assert "Found TBA episode, airing within the next 4 hours" in caplog.text + assert "Series rescan triggered" in caplog.text + + def test_when_tba_episode_has_already_aired( + self, get_serie, caplog, mocker + ) -> None: + episodes: List[json_data] = [ + self.episode_data( + id=1, + title="TBA", + airDateDelta=timedelta(days=-1), + seasonNumber=1, + ) + ] + mocker.patch.object(SonarrCli, "get_episode").return_value = episodes + + refresh_serie = mocker.patch.object(SonarrCli, "refresh_serie") + + with caplog.at_level(logging.DEBUG): + SeriesScanner("test", "test.tld", "test-api-key", 4).scan() + + assert refresh_serie.called + assert "Found previously aired episode with TBA title" in caplog.text + assert "Series rescan triggered" in caplog.text