From c21f2c6b93e4e5a8ad4ce50b9ea697bb634abf02 Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Tue, 4 Jun 2024 15:53:44 -0700 Subject: [PATCH] Added tests --- .../fast_indexing/fast_indexing_helpers.ex | 1 - lib/pinchflat/fast_indexing/youtube_api.ex | 12 ++- lib/pinchflat/sources/source.ex | 2 +- .../fast_indexing_helpers_test.exs | 62 ++++++++++++-- .../fast_indexing/youtube_api_test.exs | 85 +++++++++++++++++++ 5 files changed, 145 insertions(+), 17 deletions(-) create mode 100644 test/pinchflat/fast_indexing/youtube_api_test.exs diff --git a/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex b/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex index bad6af3..02fc00f 100644 --- a/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex +++ b/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex @@ -51,7 +51,6 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do # If possible, use the YouTube API to fetch media IDs. If that fails, fall back to the RSS feed. # If the YouTube API isn't set up, just use the RSS feed. defp get_recent_media_ids(source) do - # TODO: test with true <- YoutubeApi.enabled?(), {:ok, media_ids} <- YoutubeApi.get_recent_media_ids(source) do {:ok, media_ids} diff --git a/lib/pinchflat/fast_indexing/youtube_api.ex b/lib/pinchflat/fast_indexing/youtube_api.ex index b41450e..03796f1 100644 --- a/lib/pinchflat/fast_indexing/youtube_api.ex +++ b/lib/pinchflat/fast_indexing/youtube_api.ex @@ -5,6 +5,7 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do require Logger + alias Pinchflat.Settings alias Pinchflat.Sources.Source alias Pinchflat.Utils.FunctionUtils alias Pinchflat.FastIndexing.YoutubeBehaviour @@ -12,16 +13,14 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do @behaviour YoutubeBehaviour @doc """ - Determines if the YouTube API is enabled for fast indexing + Determines if the YouTube API is enabled for fast indexing by checking + if the user has an API key set Returns boolean() """ - # TODO: test - # TODO: update this to use a user setting @impl YoutubeBehaviour - def enabled?(), do: true + def enabled?(), do: is_binary(api_key()) - # TODO: test @doc """ Fetches the recent media IDs from the YouTube API for a given source. @@ -75,9 +74,8 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do |> FunctionUtils.wrap_ok() end - # TODO: replace this with a user setting defp api_key do - System.get_env("YOUTUBE_API_KEY") + Settings.get!(:youtube_api_key) end defp http_client do diff --git a/lib/pinchflat/sources/source.ex b/lib/pinchflat/sources/source.ex index 02af5bd..30b653f 100644 --- a/lib/pinchflat/sources/source.ex +++ b/lib/pinchflat/sources/source.ex @@ -128,7 +128,7 @@ defmodule Pinchflat.Sources.Source do @doc false def fast_index_frequency do # minutes - 15 + 10 end @doc false diff --git a/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs b/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs index 94d12aa..46f4226 100644 --- a/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs +++ b/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs @@ -6,19 +6,20 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do import Pinchflat.ProfilesFixtures alias Pinchflat.Tasks + alias Pinchflat.Settings alias Pinchflat.Media.MediaItem alias Pinchflat.Downloading.MediaDownloadWorker alias Pinchflat.FastIndexing.FastIndexingHelpers + setup do + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> + {:ok, media_attributes_return_fixture()} + end) + + {:ok, [source: source_fixture()]} + end + describe "kickoff_download_tasks_from_youtube_rss_feed/1" do - setup do - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> - {:ok, media_attributes_return_fixture()} - end) - - {:ok, [source: source_fixture()]} - end - test "enqueues a new worker for each new media_id in the source's RSS feed", %{source: source} do expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) @@ -107,4 +108,49 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do assert [] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source) end end + + describe "kickoff_download_tasks_from_youtube_rss_feed/1 when testing backends" do + test "uses the YouTube API if it is enabled", %{source: source} do + expect(HTTPClientMock, :get, fn url, _headers -> + assert url =~ "https://youtube.googleapis.com/youtube/v3/playlistItems" + + {:ok, "{}"} + end) + + Settings.set(youtube_api_key: "test_key") + + assert [] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source) + end + + test "the YouTube API creates records as expected", %{source: source} do + expect(HTTPClientMock, :get, fn _url, _headers -> + {:ok, ~s({ "items": [ {"contentDetails": {"videoId": "test_1"}} ] })} + end) + + Settings.set(youtube_api_key: "test_key") + + assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source) + end + + test "RSS is used as a backup if the API fails", %{source: source} do + expect(HTTPClientMock, :get, fn _url, _headers -> {:error, ""} end) + expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) + + Settings.set(youtube_api_key: "test_key") + + assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source) + end + + test "RSS is used if the API is not enabled", %{source: source} do + expect(HTTPClientMock, :get, fn url -> + assert url =~ "https://www.youtube.com/feeds/videos.xml" + + {:ok, "test_1"} + end) + + Settings.set(youtube_api_key: nil) + + assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source) + end + end end diff --git a/test/pinchflat/fast_indexing/youtube_api_test.exs b/test/pinchflat/fast_indexing/youtube_api_test.exs new file mode 100644 index 0000000..cc310d6 --- /dev/null +++ b/test/pinchflat/fast_indexing/youtube_api_test.exs @@ -0,0 +1,85 @@ +defmodule Pinchflat.FastIndexing.YoutubeApiTest do + use Pinchflat.DataCase + + import Pinchflat.SourcesFixtures + + alias Pinchflat.Settings + alias Pinchflat.FastIndexing.YoutubeApi + + describe "enabled?/0" do + test "returns true if the user has set a YouTube API key" do + Settings.set(youtube_api_key: "test_key") + + assert YoutubeApi.enabled?() + end + + test "returns false if the user has not set an API key" do + Settings.set(youtube_api_key: nil) + + refute YoutubeApi.enabled?() + end + end + + describe "get_recent_media_ids/1" do + setup do + source = source_fixture() + Settings.set(youtube_api_key: "test_key") + + {:ok, source: source} + end + + test "calls the expected URL", %{source: source} do + expect(HTTPClientMock, :get, fn url, headers -> + api_base = "https://youtube.googleapis.com/youtube/v3/playlistItems" + request_url = "#{api_base}?part=contentDetails&maxResults=50&playlistId=#{source.collection_id}&key=test_key" + + assert url == request_url + assert headers == [accept: "application/json"] + + {:ok, "{}"} + end) + + assert {:ok, _} = YoutubeApi.get_recent_media_ids(source) + end + + test "replaces channel IDs with playlist IDs if needed" do + source = source_fixture(collection_id: "UC_ABC123") + + expect(HTTPClientMock, :get, fn url, _headers -> + assert url =~ "playlistId=UU_ABC123&" + + {:ok, "{}"} + end) + + assert {:ok, _} = YoutubeApi.get_recent_media_ids(source) + end + + test "returns an empty list if no media is returned", %{source: source} do + expect(HTTPClientMock, :get, fn _url, _headers -> {:ok, "{}"} end) + + assert {:ok, []} = YoutubeApi.get_recent_media_ids(source) + end + + test "returns media IDs if present", %{source: source} do + expect(HTTPClientMock, :get, fn _url, _headers -> + {:ok, + """ + { + "items": [ + {"contentDetails": {"videoId": "test_1"}}, + {"contentDetails": {"videoId": "test_2"}} + ] + } + """} + end) + + assert {:ok, ["test_1", "test_2"]} = YoutubeApi.get_recent_media_ids(source) + end + + test "returns an error if the HTTP request fails", %{source: source} do + expect(HTTPClientMock, :get, fn _url, _headers -> {:error, "error"} end) + + assert {:error, "error"} = YoutubeApi.get_recent_media_ids(source) + end + end +end