Change Channel to Source (#12)
* Ensure channel detail lookup doesn't download the video - oops * Ran the needful migrations for replacing channels with sources * got media source test back working * channel tasks test * Media indexing worker test * media tests * Got all tests working except controller tests * got all tests working * Renamed Channel struct to Source * renamed ChannelTasks * More renaming; renamed channel details module * Removed Channel yt-dlp module, instead throwing things in the VideoCollection module * Renamed what looks like the last of the outstanding data
This commit is contained in:
@@ -1,45 +0,0 @@
|
||||
defmodule Pinchflat.MediaClient.Backends.YtDlp.ChannelTest do
|
||||
use ExUnit.Case, async: true
|
||||
import Mox
|
||||
|
||||
alias Pinchflat.MediaClient.ChannelDetails
|
||||
alias Pinchflat.MediaClient.Backends.YtDlp.Channel
|
||||
|
||||
@channel_url "https://www.youtube.com/c/TheUselessTrials"
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
describe "get_channel_details/1" do
|
||||
test "it returns a %ChannelDetails{} with data on success" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
|
||||
{:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"}
|
||||
end)
|
||||
|
||||
assert {:ok, res} = Channel.get_channel_details(@channel_url)
|
||||
assert %ChannelDetails{id: "UCQH2", name: "TheUselessTrials"} = res
|
||||
end
|
||||
|
||||
test "it passes the expected args to the backend runner" do
|
||||
expect(YtDlpRunnerMock, :run, fn @channel_url, opts, ot ->
|
||||
assert opts == [playlist_end: 1]
|
||||
assert ot == "%(.{channel,channel_id})j"
|
||||
|
||||
{:ok, "{}"}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = Channel.get_channel_details(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns an error if the runner returns an error" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end)
|
||||
|
||||
assert {:error, "Big issue", 1} = Channel.get_channel_details(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns an error if the output is not JSON" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "Not JSON"} end)
|
||||
|
||||
assert {:error, %Jason.DecodeError{}} = Channel.get_channel_details(@channel_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,13 +2,10 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
|
||||
use ExUnit.Case, async: true
|
||||
import Mox
|
||||
|
||||
alias Pinchflat.MediaClient.SourceDetails
|
||||
alias Pinchflat.MediaClient.Backends.YtDlp.VideoCollection
|
||||
|
||||
@channel_url "https://www.youtube.com/@TheUselessTrials"
|
||||
|
||||
defmodule VideoCollectionUser do
|
||||
use VideoCollection
|
||||
end
|
||||
@channel_url "https://www.youtube.com/c/TheUselessTrials"
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
@@ -16,7 +13,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
|
||||
test "returns a list of video ids with no blank elements" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "id1\nid2\n\nid3\n"} end)
|
||||
|
||||
assert {:ok, ["id1", "id2", "id3"]} = VideoCollectionUser.get_video_ids(@channel_url)
|
||||
assert {:ok, ["id1", "id2", "id3"]} = VideoCollection.get_video_ids(@channel_url)
|
||||
end
|
||||
|
||||
test "it passes the expected default args" do
|
||||
@@ -27,7 +24,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
|
||||
{:ok, ""}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = VideoCollectionUser.get_video_ids(@channel_url)
|
||||
assert {:ok, _} = VideoCollection.get_video_ids(@channel_url)
|
||||
end
|
||||
|
||||
test "it passes the expected custom args" do
|
||||
@@ -37,13 +34,47 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
|
||||
{:ok, ""}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = VideoCollectionUser.get_video_ids(@channel_url, [:custom_arg])
|
||||
assert {:ok, _} = VideoCollection.get_video_ids(@channel_url, [:custom_arg])
|
||||
end
|
||||
|
||||
test "returns the error straight through when the command fails" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end)
|
||||
|
||||
assert {:error, "Big issue", 1} = VideoCollectionUser.get_video_ids(@channel_url)
|
||||
assert {:error, "Big issue", 1} = VideoCollection.get_video_ids(@channel_url)
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_source_details/1" do
|
||||
test "it returns a %SourceDetails{} with data on success" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
|
||||
{:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"}
|
||||
end)
|
||||
|
||||
assert {:ok, res} = VideoCollection.get_source_details(@channel_url)
|
||||
assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} = res
|
||||
end
|
||||
|
||||
test "it passes the expected args to the backend runner" do
|
||||
expect(YtDlpRunnerMock, :run, fn @channel_url, opts, ot ->
|
||||
assert opts == [:skip_download, playlist_end: 1]
|
||||
assert ot == "%(.{channel,channel_id})j"
|
||||
|
||||
{:ok, "{}"}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = VideoCollection.get_source_details(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns an error if the runner returns an error" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end)
|
||||
|
||||
assert {:error, "Big issue", 1} = VideoCollection.get_source_details(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns an error if the output is not JSON" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "Not JSON"} end)
|
||||
|
||||
assert {:error, %Jason.DecodeError{}} = VideoCollection.get_source_details(@channel_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+11
-11
@@ -1,8 +1,8 @@
|
||||
defmodule Pinchflat.MediaClient.ChannelDetailsTest do
|
||||
defmodule Pinchflat.MediaClient.SourceDetailsTest do
|
||||
use ExUnit.Case, async: true
|
||||
import Mox
|
||||
|
||||
alias Pinchflat.MediaClient.ChannelDetails
|
||||
alias Pinchflat.MediaClient.SourceDetails
|
||||
|
||||
@channel_url "https://www.youtube.com/c/TheUselessTrials"
|
||||
|
||||
@@ -10,21 +10,21 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do
|
||||
|
||||
describe "new/2" do
|
||||
test "it returns a struct with the given values" do
|
||||
assert %ChannelDetails{id: "UCQH2", name: "TheUselessTrials"} =
|
||||
ChannelDetails.new("UCQH2", "TheUselessTrials")
|
||||
assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} =
|
||||
SourceDetails.new("UCQH2", "TheUselessTrials")
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_channel_details/2" do
|
||||
describe "get_source_details/2" do
|
||||
test "it passes the expected arguments to the backend" do
|
||||
expect(YtDlpRunnerMock, :run, fn @channel_url, opts, ot ->
|
||||
assert opts == [playlist_end: 1]
|
||||
assert opts == [:skip_download, playlist_end: 1]
|
||||
assert ot == "%(.{channel,channel_id})j"
|
||||
|
||||
{:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = ChannelDetails.get_channel_details(@channel_url)
|
||||
assert {:ok, _} = SourceDetails.get_source_details(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns a struct composed of the returned data" do
|
||||
@@ -32,8 +32,8 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do
|
||||
{:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"}
|
||||
end)
|
||||
|
||||
assert {:ok, res} = ChannelDetails.get_channel_details(@channel_url)
|
||||
assert %ChannelDetails{id: "UCQH2", name: "TheUselessTrials"} = res
|
||||
assert {:ok, res} = SourceDetails.get_source_details(@channel_url)
|
||||
assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} = res
|
||||
end
|
||||
end
|
||||
|
||||
@@ -46,7 +46,7 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do
|
||||
{:ok, ""}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = ChannelDetails.get_video_ids(@channel_url)
|
||||
assert {:ok, _} = SourceDetails.get_video_ids(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns a list of strings" do
|
||||
@@ -54,7 +54,7 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do
|
||||
{:ok, "video1\nvideo2\nvideo3"}
|
||||
end)
|
||||
|
||||
assert {:ok, ["video1", "video2", "video3"]} = ChannelDetails.get_video_ids(@channel_url)
|
||||
assert {:ok, ["video1", "video2", "video3"]} = SourceDetails.get_video_ids(@channel_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -11,7 +11,7 @@ defmodule Pinchflat.MediaClient.VideoDownloaderTest do
|
||||
media_item =
|
||||
Repo.preload(
|
||||
media_item_fixture(%{title: nil, media_filepath: nil}),
|
||||
[:metadata, channel: :media_profile]
|
||||
[:metadata, source: :media_profile]
|
||||
)
|
||||
|
||||
{:ok, %{media_item: media_item}}
|
||||
|
||||
@@ -7,82 +7,85 @@ defmodule Pinchflat.MediaSourceTest do
|
||||
|
||||
alias Pinchflat.MediaSource
|
||||
alias Pinchflat.Media.MediaItem
|
||||
alias Pinchflat.MediaSource.Channel
|
||||
alias Pinchflat.MediaSource.Source
|
||||
alias Pinchflat.Workers.MediaIndexingWorker
|
||||
|
||||
@invalid_channel_attrs %{name: nil, channel_id: nil}
|
||||
@invalid_source_attrs %{name: nil, collection_id: nil}
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
describe "list_channels/0" do
|
||||
test "it returns all channels" do
|
||||
channel = channel_fixture()
|
||||
assert MediaSource.list_channels() == [channel]
|
||||
describe "list_sources/0" do
|
||||
test "it returns all sources" do
|
||||
source = source_fixture()
|
||||
assert MediaSource.list_sources() == [source]
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_channel!/1" do
|
||||
test "it returns the channel with given id" do
|
||||
channel = channel_fixture()
|
||||
assert MediaSource.get_channel!(channel.id) == channel
|
||||
describe "get_source!/1" do
|
||||
test "it returns the source with given id" do
|
||||
source = source_fixture()
|
||||
assert MediaSource.get_source!(source.id) == source
|
||||
end
|
||||
end
|
||||
|
||||
describe "create_channel/1" do
|
||||
test "creates a channel and adds name + ID from runner response" do
|
||||
describe "create_source/1" do
|
||||
test "creates a source and adds name + ID from runner response" do
|
||||
expect(YtDlpRunnerMock, :run, &runner_function_mock/3)
|
||||
|
||||
valid_attrs = %{
|
||||
media_profile_id: media_profile_fixture().id,
|
||||
original_url: "https://www.youtube.com/channel/abc123"
|
||||
original_url: "https://www.youtube.com/channel/abc123",
|
||||
collection_type: "channel"
|
||||
}
|
||||
|
||||
assert {:ok, %Channel{} = channel} = MediaSource.create_channel(valid_attrs)
|
||||
assert channel.name == "some name"
|
||||
assert String.starts_with?(channel.channel_id, "some_channel_id_")
|
||||
assert {:ok, %Source{} = source} = MediaSource.create_source(valid_attrs)
|
||||
assert source.name == "some name"
|
||||
assert String.starts_with?(source.collection_id, "some_source_id_")
|
||||
end
|
||||
|
||||
test "creation with invalid data returns error changeset" do
|
||||
assert {:error, %Ecto.Changeset{}} = MediaSource.create_channel(@invalid_channel_attrs)
|
||||
assert {:error, %Ecto.Changeset{}} = MediaSource.create_source(@invalid_source_attrs)
|
||||
end
|
||||
|
||||
test "creation enforces uniqueness of channel_id scoped to the media_profile" do
|
||||
test "creation enforces uniqueness of source_id scoped to the media_profile" do
|
||||
expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot ->
|
||||
{:ok,
|
||||
Phoenix.json_library().encode!(%{
|
||||
channel: "some name",
|
||||
channel_id: "some_channel_id_12345678"
|
||||
channel_id: "some_source_id_12345678"
|
||||
})}
|
||||
end)
|
||||
|
||||
valid_once_attrs = %{
|
||||
media_profile_id: media_profile_fixture().id,
|
||||
original_url: "https://www.youtube.com/channel/abc123"
|
||||
original_url: "https://www.youtube.com/channel/abc123",
|
||||
collection_type: "channel"
|
||||
}
|
||||
|
||||
assert {:ok, %Channel{}} = MediaSource.create_channel(valid_once_attrs)
|
||||
assert {:error, %Ecto.Changeset{}} = MediaSource.create_channel(valid_once_attrs)
|
||||
assert {:ok, %Source{}} = MediaSource.create_source(valid_once_attrs)
|
||||
assert {:error, %Ecto.Changeset{}} = MediaSource.create_source(valid_once_attrs)
|
||||
end
|
||||
|
||||
test "creation lets you duplicate channel_ids as long as the media profile is different" do
|
||||
test "creation lets you duplicate collection_ids as long as the media profile is different" do
|
||||
expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot ->
|
||||
{:ok,
|
||||
Phoenix.json_library().encode!(%{
|
||||
channel: "some name",
|
||||
channel_id: "some_channel_id_12345678"
|
||||
channel_id: "some_source_id_12345678"
|
||||
})}
|
||||
end)
|
||||
|
||||
valid_attrs = %{
|
||||
name: "some name",
|
||||
original_url: "https://www.youtube.com/channel/abc123"
|
||||
original_url: "https://www.youtube.com/channel/abc123",
|
||||
collection_type: "channel"
|
||||
}
|
||||
|
||||
channel_1_attrs = Map.merge(valid_attrs, %{media_profile_id: media_profile_fixture().id})
|
||||
channel_2_attrs = Map.merge(valid_attrs, %{media_profile_id: media_profile_fixture().id})
|
||||
source_1_attrs = Map.merge(valid_attrs, %{media_profile_id: media_profile_fixture().id})
|
||||
source_2_attrs = Map.merge(valid_attrs, %{media_profile_id: media_profile_fixture().id})
|
||||
|
||||
assert {:ok, %Channel{}} = MediaSource.create_channel(channel_1_attrs)
|
||||
assert {:ok, %Channel{}} = MediaSource.create_channel(channel_2_attrs)
|
||||
assert {:ok, %Source{}} = MediaSource.create_source(source_1_attrs)
|
||||
assert {:ok, %Source{}} = MediaSource.create_source(source_2_attrs)
|
||||
end
|
||||
|
||||
test "creation will schedule the indexing task" do
|
||||
@@ -90,12 +93,13 @@ defmodule Pinchflat.MediaSourceTest do
|
||||
|
||||
valid_attrs = %{
|
||||
media_profile_id: media_profile_fixture().id,
|
||||
original_url: "https://www.youtube.com/channel/abc123"
|
||||
original_url: "https://www.youtube.com/channel/abc123",
|
||||
collection_type: "channel"
|
||||
}
|
||||
|
||||
assert {:ok, %Channel{} = channel} = MediaSource.create_channel(valid_attrs)
|
||||
assert {:ok, %Source{} = source} = MediaSource.create_source(valid_attrs)
|
||||
|
||||
assert_enqueued(worker: MediaIndexingWorker, args: %{"id" => channel.id})
|
||||
assert_enqueued(worker: MediaIndexingWorker, args: %{"id" => source.id})
|
||||
end
|
||||
end
|
||||
|
||||
@@ -103,181 +107,181 @@ defmodule Pinchflat.MediaSourceTest do
|
||||
setup do
|
||||
stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "video1\nvideo2\nvideo3"} end)
|
||||
|
||||
{:ok, [channel: channel_fixture()]}
|
||||
{:ok, [source: source_fixture()]}
|
||||
end
|
||||
|
||||
test "it creates a media_item record for each media ID returned", %{channel: channel} do
|
||||
assert media_items = MediaSource.index_media_items(channel)
|
||||
test "it creates a media_item record for each media ID returned", %{source: source} do
|
||||
assert media_items = MediaSource.index_media_items(source)
|
||||
|
||||
assert Enum.count(media_items) == 3
|
||||
assert ["video1", "video2", "video3"] == Enum.map(media_items, & &1.media_id)
|
||||
assert Enum.all?(media_items, fn %MediaItem{} -> true end)
|
||||
end
|
||||
|
||||
test "it attaches all media_items to the given channel", %{channel: channel} do
|
||||
channel_id = channel.id
|
||||
assert media_items = MediaSource.index_media_items(channel)
|
||||
test "it attaches all media_items to the given source", %{source: source} do
|
||||
source_id = source.id
|
||||
assert media_items = MediaSource.index_media_items(source)
|
||||
|
||||
assert Enum.count(media_items) == 3
|
||||
assert Enum.all?(media_items, fn %MediaItem{channel_id: ^channel_id} -> true end)
|
||||
assert Enum.all?(media_items, fn %MediaItem{source_id: ^source_id} -> true end)
|
||||
end
|
||||
|
||||
test "it won't duplicate media_items based on media_id and channel", %{channel: channel} do
|
||||
_first_run = MediaSource.index_media_items(channel)
|
||||
_duplicate_run = MediaSource.index_media_items(channel)
|
||||
test "it won't duplicate media_items based on media_id and source", %{source: source} do
|
||||
_first_run = MediaSource.index_media_items(source)
|
||||
_duplicate_run = MediaSource.index_media_items(source)
|
||||
|
||||
media_items = Repo.preload(channel, :media_items).media_items
|
||||
media_items = Repo.preload(source, :media_items).media_items
|
||||
assert Enum.count(media_items) == 3
|
||||
end
|
||||
|
||||
test "it can duplicate media_ids for different channels", %{channel: channel} do
|
||||
other_channel = channel_fixture()
|
||||
test "it can duplicate media_ids for different sources", %{source: source} do
|
||||
other_source = source_fixture()
|
||||
|
||||
media_items = MediaSource.index_media_items(channel)
|
||||
media_items_other_channel = MediaSource.index_media_items(other_channel)
|
||||
media_items = MediaSource.index_media_items(source)
|
||||
media_items_other_source = MediaSource.index_media_items(other_source)
|
||||
|
||||
assert Enum.count(media_items) == 3
|
||||
assert Enum.count(media_items_other_channel) == 3
|
||||
assert Enum.count(media_items_other_source) == 3
|
||||
|
||||
assert Enum.map(media_items, & &1.media_id) ==
|
||||
Enum.map(media_items_other_channel, & &1.media_id)
|
||||
Enum.map(media_items_other_source, & &1.media_id)
|
||||
end
|
||||
|
||||
test "it returns a list of media_items or changesets", %{channel: channel} do
|
||||
first_run = MediaSource.index_media_items(channel)
|
||||
duplicate_run = MediaSource.index_media_items(channel)
|
||||
test "it returns a list of media_items or changesets", %{source: source} do
|
||||
first_run = MediaSource.index_media_items(source)
|
||||
duplicate_run = MediaSource.index_media_items(source)
|
||||
|
||||
assert Enum.all?(first_run, fn %MediaItem{} -> true end)
|
||||
assert Enum.all?(duplicate_run, fn %Ecto.Changeset{} -> true end)
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_channel/2" do
|
||||
test "updates with valid data updates the channel" do
|
||||
channel = channel_fixture()
|
||||
describe "update_source/2" do
|
||||
test "updates with valid data updates the source" do
|
||||
source = source_fixture()
|
||||
update_attrs = %{name: "some updated name"}
|
||||
|
||||
assert {:ok, %Channel{} = channel} = MediaSource.update_channel(channel, update_attrs)
|
||||
assert channel.name == "some updated name"
|
||||
assert {:ok, %Source{} = source} = MediaSource.update_source(source, update_attrs)
|
||||
assert source.name == "some updated name"
|
||||
end
|
||||
|
||||
test "updating the original_url will re-fetch the channel details" do
|
||||
test "updating the original_url will re-fetch the source details" do
|
||||
expect(YtDlpRunnerMock, :run, &runner_function_mock/3)
|
||||
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
update_attrs = %{original_url: "https://www.youtube.com/channel/abc123"}
|
||||
|
||||
assert {:ok, %Channel{} = channel} = MediaSource.update_channel(channel, update_attrs)
|
||||
assert channel.name == "some name"
|
||||
assert String.starts_with?(channel.channel_id, "some_channel_id_")
|
||||
assert {:ok, %Source{} = source} = MediaSource.update_source(source, update_attrs)
|
||||
assert source.name == "some name"
|
||||
assert String.starts_with?(source.collection_id, "some_source_id_")
|
||||
end
|
||||
|
||||
test "not updating the original_url will not re-fetch the channel details" do
|
||||
test "not updating the original_url will not re-fetch the source details" do
|
||||
expect(YtDlpRunnerMock, :run, 0, &runner_function_mock/3)
|
||||
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
update_attrs = %{name: "some updated name"}
|
||||
|
||||
assert {:ok, %Channel{}} = MediaSource.update_channel(channel, update_attrs)
|
||||
assert {:ok, %Source{}} = MediaSource.update_source(source, update_attrs)
|
||||
end
|
||||
|
||||
test "updating the index frequency will re-schedule the indexing task" do
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
update_attrs = %{index_frequency_minutes: 123}
|
||||
|
||||
assert {:ok, %Channel{} = channel} = MediaSource.update_channel(channel, update_attrs)
|
||||
assert channel.index_frequency_minutes == 123
|
||||
assert_enqueued(worker: MediaIndexingWorker, args: %{"id" => channel.id})
|
||||
assert {:ok, %Source{} = source} = MediaSource.update_source(source, update_attrs)
|
||||
assert source.index_frequency_minutes == 123
|
||||
assert_enqueued(worker: MediaIndexingWorker, args: %{"id" => source.id})
|
||||
end
|
||||
|
||||
test "not updating the index frequency will not re-schedule the indexing task" do
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
update_attrs = %{name: "some updated name"}
|
||||
|
||||
assert {:ok, %Channel{}} = MediaSource.update_channel(channel, update_attrs)
|
||||
refute_enqueued(worker: MediaIndexingWorker, args: %{"id" => channel.id})
|
||||
assert {:ok, %Source{}} = MediaSource.update_source(source, update_attrs)
|
||||
refute_enqueued(worker: MediaIndexingWorker, args: %{"id" => source.id})
|
||||
end
|
||||
|
||||
test "updates with invalid data returns error changeset" do
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
|
||||
assert {:error, %Ecto.Changeset{}} =
|
||||
MediaSource.update_channel(channel, @invalid_channel_attrs)
|
||||
MediaSource.update_source(source, @invalid_source_attrs)
|
||||
|
||||
assert channel == MediaSource.get_channel!(channel.id)
|
||||
assert source == MediaSource.get_source!(source.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_channel/1" do
|
||||
test "it deletes the channel" do
|
||||
channel = channel_fixture()
|
||||
assert {:ok, %Channel{}} = MediaSource.delete_channel(channel)
|
||||
assert_raise Ecto.NoResultsError, fn -> MediaSource.get_channel!(channel.id) end
|
||||
describe "delete_source/1" do
|
||||
test "it deletes the source" do
|
||||
source = source_fixture()
|
||||
assert {:ok, %Source{}} = MediaSource.delete_source(source)
|
||||
assert_raise Ecto.NoResultsError, fn -> MediaSource.get_source!(source.id) end
|
||||
end
|
||||
|
||||
test "it returns a channel changeset" do
|
||||
channel = channel_fixture()
|
||||
assert %Ecto.Changeset{} = MediaSource.change_channel(channel)
|
||||
test "it returns a source changeset" do
|
||||
source = source_fixture()
|
||||
assert %Ecto.Changeset{} = MediaSource.change_source(source)
|
||||
end
|
||||
|
||||
test "deletion also deletes all associated tasks" do
|
||||
channel = channel_fixture()
|
||||
task = task_fixture(channel_id: channel.id)
|
||||
source = source_fixture()
|
||||
task = task_fixture(source_id: source.id)
|
||||
|
||||
assert {:ok, %Channel{}} = MediaSource.delete_channel(channel)
|
||||
assert {:ok, %Source{}} = MediaSource.delete_source(source)
|
||||
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end
|
||||
end
|
||||
end
|
||||
|
||||
describe "change_channel/2" do
|
||||
describe "change_source/2" do
|
||||
test "it returns a changeset" do
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
|
||||
assert %Ecto.Changeset{} = MediaSource.change_channel(channel)
|
||||
assert %Ecto.Changeset{} = MediaSource.change_source(source)
|
||||
end
|
||||
end
|
||||
|
||||
describe "change_channel_from_url/2" do
|
||||
describe "change_source_from_url/2" do
|
||||
test "it returns a changeset" do
|
||||
stub(YtDlpRunnerMock, :run, &runner_function_mock/3)
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
|
||||
assert %Ecto.Changeset{} = MediaSource.change_channel_from_url(channel, %{})
|
||||
assert %Ecto.Changeset{} = MediaSource.change_source_from_url(source, %{})
|
||||
end
|
||||
|
||||
test "it does not fetch channel details if the original_url isn't in the changeset" do
|
||||
test "it does not fetch source details if the original_url isn't in the changeset" do
|
||||
expect(YtDlpRunnerMock, :run, 0, &runner_function_mock/3)
|
||||
|
||||
changeset = MediaSource.change_channel_from_url(%Channel{}, %{name: "some updated name"})
|
||||
changeset = MediaSource.change_source_from_url(%Source{}, %{name: "some updated name"})
|
||||
|
||||
assert %Ecto.Changeset{} = changeset
|
||||
end
|
||||
|
||||
test "it fetches channel details if the original_url is in the changeset" do
|
||||
test "it fetches source details if the original_url is in the changeset" do
|
||||
expect(YtDlpRunnerMock, :run, &runner_function_mock/3)
|
||||
|
||||
changeset =
|
||||
MediaSource.change_channel_from_url(%Channel{}, %{
|
||||
MediaSource.change_source_from_url(%Source{}, %{
|
||||
original_url: "https://www.youtube.com/channel/abc123"
|
||||
})
|
||||
|
||||
assert %Ecto.Changeset{} = changeset
|
||||
end
|
||||
|
||||
test "it adds channel details to the changeset, keeping the orignal details" do
|
||||
test "it adds source details to the changeset, keeping the orignal details" do
|
||||
expect(YtDlpRunnerMock, :run, &runner_function_mock/3)
|
||||
|
||||
media_profile = media_profile_fixture()
|
||||
media_profile_id = media_profile.id
|
||||
|
||||
changeset =
|
||||
MediaSource.change_channel_from_url(%Channel{}, %{
|
||||
MediaSource.change_source_from_url(%Source{}, %{
|
||||
original_url: "https://www.youtube.com/channel/abc123",
|
||||
media_profile_id: media_profile.id
|
||||
})
|
||||
|
||||
assert %Ecto.Changeset{} = changeset
|
||||
assert String.starts_with?(changeset.changes.channel_id, "some_channel_id_")
|
||||
assert String.starts_with?(changeset.changes.collection_id, "some_source_id_")
|
||||
|
||||
assert %{
|
||||
name: "some name",
|
||||
@@ -292,12 +296,12 @@ defmodule Pinchflat.MediaSourceTest do
|
||||
end)
|
||||
|
||||
changeset =
|
||||
MediaSource.change_channel_from_url(%Channel{}, %{
|
||||
MediaSource.change_source_from_url(%Source{}, %{
|
||||
original_url: "https://www.youtube.com/channel/abc123"
|
||||
})
|
||||
|
||||
assert %Ecto.Changeset{} = changeset
|
||||
assert errors_on(changeset).original_url == ["could not fetch channel details from URL"]
|
||||
assert errors_on(changeset).original_url == ["could not fetch source details from URL"]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -306,7 +310,7 @@ defmodule Pinchflat.MediaSourceTest do
|
||||
:ok,
|
||||
Phoenix.json_library().encode!(%{
|
||||
channel: "some name",
|
||||
channel_id: "some_channel_id_#{:rand.uniform(1_000_000)}"
|
||||
channel_id: "some_source_id_#{:rand.uniform(1_000_000)}"
|
||||
})
|
||||
}
|
||||
end
|
||||
|
||||
@@ -30,23 +30,23 @@ defmodule Pinchflat.MediaTest do
|
||||
end
|
||||
|
||||
describe "list_pending_media_items_for/1" do
|
||||
test "it returns pending media_items for a given channel" do
|
||||
channel = channel_fixture()
|
||||
media_item = media_item_fixture(%{channel_id: channel.id, media_filepath: nil})
|
||||
test "it returns pending media_items for a given source" do
|
||||
source = source_fixture()
|
||||
media_item = media_item_fixture(%{source_id: source.id, media_filepath: nil})
|
||||
|
||||
assert Media.list_pending_media_items_for(channel) == [media_item]
|
||||
assert Media.list_pending_media_items_for(source) == [media_item]
|
||||
end
|
||||
|
||||
test "it does not return media_items with media_filepath" do
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
|
||||
_media_item =
|
||||
media_item_fixture(%{
|
||||
channel_id: channel.id,
|
||||
source_id: source.id,
|
||||
media_filepath: "/video/#{Faker.File.file_name(:video)}"
|
||||
})
|
||||
|
||||
assert Media.list_pending_media_items_for(channel) == []
|
||||
assert Media.list_pending_media_items_for(source) == []
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,7 +63,7 @@ defmodule Pinchflat.MediaTest do
|
||||
media_id: Faker.String.base64(12),
|
||||
title: Faker.Commerce.product_name(),
|
||||
media_filepath: "/video/#{Faker.File.file_name(:video)}",
|
||||
channel_id: channel_fixture().id
|
||||
source_id: source_fixture().id
|
||||
}
|
||||
|
||||
assert {:ok, %MediaItem{} = media_item} = Media.create_media_item(valid_attrs)
|
||||
@@ -85,7 +85,7 @@ defmodule Pinchflat.MediaTest do
|
||||
media_id: Faker.String.base64(12),
|
||||
title: Faker.Commerce.product_name(),
|
||||
media_filepath: "/video/#{Faker.File.file_name(:video)}",
|
||||
channel_id: channel_fixture().id
|
||||
source_id: source_fixture().id
|
||||
}
|
||||
|
||||
assert {:ok, %MediaItem{} = media_item} = Media.update_media_item(media_item, update_attrs)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
defmodule Pinchflat.Tasks.ChannelTasksTest do
|
||||
use Pinchflat.DataCase
|
||||
|
||||
import Pinchflat.TasksFixtures
|
||||
import Pinchflat.MediaSourceFixtures
|
||||
|
||||
alias Pinchflat.Tasks.Task
|
||||
alias Pinchflat.Tasks.ChannelTasks
|
||||
alias Pinchflat.Workers.MediaIndexingWorker
|
||||
|
||||
describe "kickoff_indexing_task/1" do
|
||||
test "it does not schedule a job if the interval is <= 0" do
|
||||
channel = channel_fixture(index_frequency_minutes: -1)
|
||||
|
||||
assert {:ok, :should_not_index} = ChannelTasks.kickoff_indexing_task(channel)
|
||||
|
||||
refute_enqueued(worker: MediaIndexingWorker, args: %{"id" => channel.id})
|
||||
end
|
||||
|
||||
test "it schedules a job if the interval is > 0" do
|
||||
channel = channel_fixture(index_frequency_minutes: 1)
|
||||
|
||||
assert {:ok, _} = ChannelTasks.kickoff_indexing_task(channel)
|
||||
|
||||
assert_enqueued(worker: MediaIndexingWorker, args: %{"id" => channel.id})
|
||||
end
|
||||
|
||||
test "it creates and attaches a task if the interval is > 0" do
|
||||
channel = channel_fixture(index_frequency_minutes: 1)
|
||||
|
||||
assert {:ok, %Task{} = task} = ChannelTasks.kickoff_indexing_task(channel)
|
||||
|
||||
assert task.channel_id == channel.id
|
||||
end
|
||||
|
||||
test "it deletes any pending tasks for the channel" do
|
||||
channel = channel_fixture()
|
||||
task = task_fixture(channel_id: channel.id)
|
||||
|
||||
assert {:ok, _} = ChannelTasks.kickoff_indexing_task(channel)
|
||||
|
||||
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,45 @@
|
||||
defmodule Pinchflat.Tasks.SourceTasksTest do
|
||||
use Pinchflat.DataCase
|
||||
|
||||
import Pinchflat.TasksFixtures
|
||||
import Pinchflat.MediaSourceFixtures
|
||||
|
||||
alias Pinchflat.Tasks.Task
|
||||
alias Pinchflat.Tasks.SourceTasks
|
||||
alias Pinchflat.Workers.MediaIndexingWorker
|
||||
|
||||
describe "kickoff_indexing_task/1" do
|
||||
test "it does not schedule a job if the interval is <= 0" do
|
||||
source = source_fixture(index_frequency_minutes: -1)
|
||||
|
||||
assert {:ok, :should_not_index} = SourceTasks.kickoff_indexing_task(source)
|
||||
|
||||
refute_enqueued(worker: MediaIndexingWorker, args: %{"id" => source.id})
|
||||
end
|
||||
|
||||
test "it schedules a job if the interval is > 0" do
|
||||
source = source_fixture(index_frequency_minutes: 1)
|
||||
|
||||
assert {:ok, _} = SourceTasks.kickoff_indexing_task(source)
|
||||
|
||||
assert_enqueued(worker: MediaIndexingWorker, args: %{"id" => source.id})
|
||||
end
|
||||
|
||||
test "it creates and attaches a task if the interval is > 0" do
|
||||
source = source_fixture(index_frequency_minutes: 1)
|
||||
|
||||
assert {:ok, %Task{} = task} = SourceTasks.kickoff_indexing_task(source)
|
||||
|
||||
assert task.source_id == source.id
|
||||
end
|
||||
|
||||
test "it deletes any pending tasks for the source" do
|
||||
source = source_fixture()
|
||||
task = task_fixture(source_id: source.id)
|
||||
|
||||
assert {:ok, _} = SourceTasks.kickoff_indexing_task(source)
|
||||
|
||||
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -21,11 +21,11 @@ defmodule Pinchflat.TasksTest do
|
||||
end
|
||||
|
||||
test "it does not delete the other record when a job gets deleted" do
|
||||
task = Repo.preload(task_fixture(), [:channel, :job])
|
||||
task = Repo.preload(task_fixture(), [:source, :job])
|
||||
|
||||
{:ok, _} = Repo.delete(task.job)
|
||||
|
||||
assert Repo.reload!(task.channel)
|
||||
assert Repo.reload!(task.source)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,14 +40,14 @@ defmodule Pinchflat.TasksTest do
|
||||
test "it lets you specify which record type/ID to join on" do
|
||||
task = task_fixture()
|
||||
|
||||
assert Tasks.list_tasks_for(:channel_id, task.channel_id) == [task]
|
||||
assert Tasks.list_tasks_for(:source_id, task.source_id) == [task]
|
||||
end
|
||||
|
||||
test "it lets you specify which job states to include" do
|
||||
task = task_fixture()
|
||||
|
||||
assert Tasks.list_tasks_for(:channel_id, task.channel_id, [:available]) == [task]
|
||||
assert Tasks.list_tasks_for(:channel_id, task.channel_id, [:cancelled]) == []
|
||||
assert Tasks.list_tasks_for(:source_id, task.source_id, [:available]) == [task]
|
||||
assert Tasks.list_tasks_for(:source_id, task.source_id, [:cancelled]) == []
|
||||
end
|
||||
end
|
||||
|
||||
@@ -55,14 +55,14 @@ defmodule Pinchflat.TasksTest do
|
||||
test "it lists pending tasks" do
|
||||
task = task_fixture()
|
||||
|
||||
assert Tasks.list_pending_tasks_for(:channel_id, task.channel_id) == [task]
|
||||
assert Tasks.list_pending_tasks_for(:source_id, task.source_id) == [task]
|
||||
end
|
||||
|
||||
test "it does not list non-pending tasks" do
|
||||
task = Repo.preload(task_fixture(), :job)
|
||||
:ok = Oban.cancel_job(task.job)
|
||||
|
||||
assert Tasks.list_pending_tasks_for(:channel_id, task.channel_id) == []
|
||||
assert Tasks.list_pending_tasks_for(:source_id, task.source_id) == []
|
||||
end
|
||||
end
|
||||
|
||||
@@ -84,14 +84,14 @@ defmodule Pinchflat.TasksTest do
|
||||
assert {:error, %Ecto.Changeset{}} = Tasks.create_task(@invalid_attrs)
|
||||
end
|
||||
|
||||
test "accepts a job and channel" do
|
||||
test "accepts a job and source" do
|
||||
job = job_fixture()
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
|
||||
assert {:ok, %Task{} = task} = Tasks.create_task(job, channel)
|
||||
assert {:ok, %Task{} = task} = Tasks.create_task(job, source)
|
||||
|
||||
assert task.job_id == job.id
|
||||
assert task.channel_id == channel.id
|
||||
assert task.source_id == source.id
|
||||
end
|
||||
|
||||
test "accepts a job and media item" do
|
||||
@@ -115,25 +115,25 @@ defmodule Pinchflat.TasksTest do
|
||||
end
|
||||
|
||||
test "it creates a task record if successful" do
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
|
||||
assert {:ok, %Task{} = task} = Tasks.create_job_with_task(TestJobWorker.new(%{}), channel)
|
||||
assert {:ok, %Task{} = task} = Tasks.create_job_with_task(TestJobWorker.new(%{}), source)
|
||||
|
||||
assert task.channel_id == channel.id
|
||||
assert task.source_id == source.id
|
||||
end
|
||||
|
||||
test "it returns an error if the job already exists" do
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
job = TestJobWorker.new(%{foo: "bar"}, unique: [period: :infinity])
|
||||
|
||||
assert {:ok, %Task{}} = Tasks.create_job_with_task(job, channel)
|
||||
assert {:error, :duplicate_job} = Tasks.create_job_with_task(job, channel)
|
||||
assert {:ok, %Task{}} = Tasks.create_job_with_task(job, source)
|
||||
assert {:error, :duplicate_job} = Tasks.create_job_with_task(job, source)
|
||||
end
|
||||
|
||||
test "it returns an error if the job fails to enqueue" do
|
||||
channel = channel_fixture()
|
||||
source = source_fixture()
|
||||
|
||||
assert {:error, %Ecto.Changeset{}} = Tasks.create_job_with_task(%Ecto.Changeset{}, channel)
|
||||
assert {:error, %Ecto.Changeset{}} = Tasks.create_job_with_task(%Ecto.Changeset{}, source)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -155,11 +155,11 @@ defmodule Pinchflat.TasksTest do
|
||||
end
|
||||
|
||||
describe "delete_tasks_for/1" do
|
||||
test "it deletes tasks attached to a channel" do
|
||||
channel = channel_fixture()
|
||||
task = task_fixture(channel_id: channel.id)
|
||||
test "it deletes tasks attached to a source" do
|
||||
source = source_fixture()
|
||||
task = task_fixture(source_id: source.id)
|
||||
|
||||
assert :ok = Tasks.delete_tasks_for(channel)
|
||||
assert :ok = Tasks.delete_tasks_for(source)
|
||||
assert_raise Ecto.NoResultsError, fn -> Tasks.get_task!(task.id) end
|
||||
end
|
||||
|
||||
@@ -173,20 +173,20 @@ defmodule Pinchflat.TasksTest do
|
||||
end
|
||||
|
||||
describe "delete_pending_tasks_for/1" do
|
||||
test "it deletes pending tasks attached to a channel" do
|
||||
channel = channel_fixture()
|
||||
task = task_fixture(channel_id: channel.id)
|
||||
test "it deletes pending tasks attached to a source" do
|
||||
source = source_fixture()
|
||||
task = task_fixture(source_id: source.id)
|
||||
|
||||
assert :ok = Tasks.delete_pending_tasks_for(channel)
|
||||
assert :ok = Tasks.delete_pending_tasks_for(source)
|
||||
assert_raise Ecto.NoResultsError, fn -> Tasks.get_task!(task.id) end
|
||||
end
|
||||
|
||||
test "it does not delete non-pending tasks" do
|
||||
channel = channel_fixture()
|
||||
task = Repo.preload(task_fixture(channel_id: channel.id), :job)
|
||||
source = source_fixture()
|
||||
task = Repo.preload(task_fixture(source_id: source.id), :job)
|
||||
:ok = Oban.cancel_job(task.job)
|
||||
|
||||
assert :ok = Tasks.delete_pending_tasks_for(channel)
|
||||
assert :ok = Tasks.delete_pending_tasks_for(source)
|
||||
assert Tasks.get_task!(task.id)
|
||||
end
|
||||
|
||||
|
||||
@@ -12,36 +12,36 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
|
||||
setup :verify_on_exit!
|
||||
|
||||
describe "perform/1" do
|
||||
test "it does not do any indexing if the channel shouldn't be indexed" do
|
||||
test "it does not do any indexing if the source shouldn't be indexed" do
|
||||
expect(YtDlpRunnerMock, :run, 0, fn _url, _opts, _ot -> {:ok, ""} end)
|
||||
|
||||
channel = channel_fixture(index_frequency_minutes: -1)
|
||||
source = source_fixture(index_frequency_minutes: -1)
|
||||
|
||||
perform_job(MediaIndexingWorker, %{id: channel.id})
|
||||
perform_job(MediaIndexingWorker, %{id: source.id})
|
||||
end
|
||||
|
||||
test "it does not reschedule if the channel shouldn't be indexed" do
|
||||
test "it does not reschedule if the source shouldn't be indexed" do
|
||||
expect(YtDlpRunnerMock, :run, 0, fn _url, _opts, _ot -> {:ok, ""} end)
|
||||
|
||||
channel = channel_fixture(index_frequency_minutes: -1)
|
||||
perform_job(MediaIndexingWorker, %{id: channel.id})
|
||||
source = source_fixture(index_frequency_minutes: -1)
|
||||
perform_job(MediaIndexingWorker, %{id: source.id})
|
||||
|
||||
refute_enqueued(worker: MediaIndexingWorker, args: %{"id" => channel.id})
|
||||
refute_enqueued(worker: MediaIndexingWorker, args: %{"id" => source.id})
|
||||
end
|
||||
|
||||
test "it indexes the channel if it should be indexed" do
|
||||
test "it indexes the source if it should be indexed" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end)
|
||||
|
||||
channel = channel_fixture(index_frequency_minutes: 10)
|
||||
source = source_fixture(index_frequency_minutes: 10)
|
||||
|
||||
perform_job(MediaIndexingWorker, %{id: channel.id})
|
||||
perform_job(MediaIndexingWorker, %{id: source.id})
|
||||
end
|
||||
|
||||
test "it kicks off a download job for each pending media item" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "video1"} end)
|
||||
|
||||
channel = channel_fixture(index_frequency_minutes: 10)
|
||||
perform_job(MediaIndexingWorker, %{id: channel.id})
|
||||
source = source_fixture(index_frequency_minutes: 10)
|
||||
perform_job(MediaIndexingWorker, %{id: source.id})
|
||||
|
||||
assert [_] = all_enqueued(worker: VideoDownloadWorker)
|
||||
end
|
||||
@@ -49,9 +49,9 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
|
||||
test "it starts a job for any pending media item even if it's from another run" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "video1"} end)
|
||||
|
||||
channel = channel_fixture(index_frequency_minutes: 10)
|
||||
media_item_fixture(%{channel_id: channel.id, media_filepath: nil})
|
||||
perform_job(MediaIndexingWorker, %{id: channel.id})
|
||||
source = source_fixture(index_frequency_minutes: 10)
|
||||
media_item_fixture(%{source_id: source.id, media_filepath: nil})
|
||||
perform_job(MediaIndexingWorker, %{id: source.id})
|
||||
|
||||
assert [_, _] = all_enqueued(worker: VideoDownloadWorker)
|
||||
end
|
||||
@@ -59,8 +59,8 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
|
||||
test "it does not kick off a job for media items that could not be saved" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "video1\nvideo1"} end)
|
||||
|
||||
channel = channel_fixture(index_frequency_minutes: 10)
|
||||
perform_job(MediaIndexingWorker, %{id: channel.id})
|
||||
source = source_fixture(index_frequency_minutes: 10)
|
||||
perform_job(MediaIndexingWorker, %{id: source.id})
|
||||
|
||||
# Only one job should be enqueued, since the second video is a duplicate
|
||||
assert [_] = all_enqueued(worker: VideoDownloadWorker)
|
||||
@@ -69,41 +69,41 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
|
||||
test "it reschedules the job based on the index frequency" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end)
|
||||
|
||||
channel = channel_fixture(index_frequency_minutes: 10)
|
||||
perform_job(MediaIndexingWorker, %{id: channel.id})
|
||||
source = source_fixture(index_frequency_minutes: 10)
|
||||
perform_job(MediaIndexingWorker, %{id: source.id})
|
||||
|
||||
assert_enqueued(
|
||||
worker: MediaIndexingWorker,
|
||||
args: %{"id" => channel.id},
|
||||
scheduled_at: now_plus(channel.index_frequency_minutes, :minutes)
|
||||
args: %{"id" => source.id},
|
||||
scheduled_at: now_plus(source.index_frequency_minutes, :minutes)
|
||||
)
|
||||
end
|
||||
|
||||
test "it creates a task for the rescheduled job" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end)
|
||||
|
||||
channel = channel_fixture(index_frequency_minutes: 10)
|
||||
source = source_fixture(index_frequency_minutes: 10)
|
||||
task_count_fetcher = fn -> Enum.count(Tasks.list_tasks()) end
|
||||
|
||||
assert_changed([from: 0, to: 1], task_count_fetcher, fn ->
|
||||
perform_job(MediaIndexingWorker, %{id: channel.id})
|
||||
perform_job(MediaIndexingWorker, %{id: source.id})
|
||||
end)
|
||||
end
|
||||
|
||||
test "it creates the basic media_item records" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "video1\nvideo2"} end)
|
||||
|
||||
channel = channel_fixture(index_frequency_minutes: 10)
|
||||
source = source_fixture(index_frequency_minutes: 10)
|
||||
|
||||
media_item_fetcher = fn ->
|
||||
channel
|
||||
source
|
||||
|> Repo.preload(:media_items)
|
||||
|> Map.get(:media_items)
|
||||
|> Enum.map(fn media_item -> media_item.media_id end)
|
||||
end
|
||||
|
||||
assert_changed([from: [], to: ["video1", "video2"]], media_item_fetcher, fn ->
|
||||
perform_job(MediaIndexingWorker, %{id: channel.id})
|
||||
perform_job(MediaIndexingWorker, %{id: source.id})
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,7 +12,7 @@ defmodule Pinchflat.Workers.VideoDownloadWorkerTest do
|
||||
media_item =
|
||||
Repo.preload(
|
||||
media_item_fixture(%{media_filepath: nil}),
|
||||
[:metadata, channel: :media_profile]
|
||||
[:metadata, source: :media_profile]
|
||||
)
|
||||
|
||||
{:ok, %{media_item: media_item}}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
defmodule PinchflatWeb.ChannelControllerTest do
|
||||
use PinchflatWeb.ConnCase
|
||||
import Mox
|
||||
|
||||
import Pinchflat.ProfilesFixtures
|
||||
import Pinchflat.MediaSourceFixtures
|
||||
|
||||
setup do
|
||||
media_profile = media_profile_fixture()
|
||||
|
||||
{
|
||||
:ok,
|
||||
%{
|
||||
create_attrs: %{
|
||||
media_profile_id: media_profile.id,
|
||||
original_url: "https://www.youtube.com/channel/abc123"
|
||||
},
|
||||
update_attrs: %{
|
||||
original_url: "https://www.youtube.com/channel/321xyz"
|
||||
},
|
||||
invalid_attrs: %{original_url: nil, media_profile_id: nil}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
describe "index" do
|
||||
test "lists all channels", %{conn: conn} do
|
||||
conn = get(conn, ~p"/media_sources/channels")
|
||||
assert html_response(conn, 200) =~ "Listing Channels"
|
||||
end
|
||||
end
|
||||
|
||||
describe "new channel" do
|
||||
test "renders form", %{conn: conn} do
|
||||
conn = get(conn, ~p"/media_sources/channels/new")
|
||||
assert html_response(conn, 200) =~ "New Channel"
|
||||
end
|
||||
end
|
||||
|
||||
describe "create channel" do
|
||||
test "redirects to show when data is valid", %{conn: conn, create_attrs: create_attrs} do
|
||||
expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3)
|
||||
conn = post(conn, ~p"/media_sources/channels", channel: create_attrs)
|
||||
|
||||
assert %{id: id} = redirected_params(conn)
|
||||
assert redirected_to(conn) == ~p"/media_sources/channels/#{id}"
|
||||
|
||||
conn = get(conn, ~p"/media_sources/channels/#{id}")
|
||||
assert html_response(conn, 200) =~ "Channel #{id}"
|
||||
end
|
||||
|
||||
test "renders errors when data is invalid", %{conn: conn, invalid_attrs: invalid_attrs} do
|
||||
conn = post(conn, ~p"/media_sources/channels", channel: invalid_attrs)
|
||||
assert html_response(conn, 200) =~ "New Channel"
|
||||
end
|
||||
end
|
||||
|
||||
describe "edit channel" do
|
||||
setup [:create_channel]
|
||||
|
||||
test "renders form for editing chosen channel", %{conn: conn, channel: channel} do
|
||||
conn = get(conn, ~p"/media_sources/channels/#{channel}/edit")
|
||||
assert html_response(conn, 200) =~ "Edit Channel"
|
||||
end
|
||||
end
|
||||
|
||||
describe "update channel" do
|
||||
setup [:create_channel]
|
||||
|
||||
test "redirects when data is valid", %{conn: conn, channel: channel, update_attrs: update_attrs} do
|
||||
expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3)
|
||||
|
||||
conn = put(conn, ~p"/media_sources/channels/#{channel}", channel: update_attrs)
|
||||
assert redirected_to(conn) == ~p"/media_sources/channels/#{channel}"
|
||||
|
||||
conn = get(conn, ~p"/media_sources/channels/#{channel}")
|
||||
assert html_response(conn, 200) =~ "https://www.youtube.com/channel/321xyz"
|
||||
end
|
||||
|
||||
test "renders errors when data is invalid", %{
|
||||
conn: conn,
|
||||
channel: channel,
|
||||
invalid_attrs: invalid_attrs
|
||||
} do
|
||||
conn = put(conn, ~p"/media_sources/channels/#{channel}", channel: invalid_attrs)
|
||||
assert html_response(conn, 200) =~ "Edit Channel"
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete channel" do
|
||||
setup [:create_channel]
|
||||
|
||||
test "deletes chosen channel", %{conn: conn, channel: channel} do
|
||||
conn = delete(conn, ~p"/media_sources/channels/#{channel}")
|
||||
assert redirected_to(conn) == ~p"/media_sources/channels"
|
||||
|
||||
assert_error_sent 404, fn ->
|
||||
get(conn, ~p"/media_sources/channels/#{channel}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp create_channel(_) do
|
||||
channel = channel_fixture()
|
||||
%{channel: channel}
|
||||
end
|
||||
|
||||
defp runner_function_mock(_url, _opts, _ot) do
|
||||
{
|
||||
:ok,
|
||||
Phoenix.json_library().encode!(%{
|
||||
channel: "some name",
|
||||
channel_id: "some_channel_id_#{:rand.uniform(1_000_000)}"
|
||||
})
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,120 @@
|
||||
defmodule PinchflatWeb.SourceControllerTest do
|
||||
use PinchflatWeb.ConnCase
|
||||
import Mox
|
||||
|
||||
import Pinchflat.ProfilesFixtures
|
||||
import Pinchflat.MediaSourceFixtures
|
||||
|
||||
setup do
|
||||
media_profile = media_profile_fixture()
|
||||
|
||||
{
|
||||
:ok,
|
||||
%{
|
||||
create_attrs: %{
|
||||
media_profile_id: media_profile.id,
|
||||
collection_type: "channel",
|
||||
original_url: "https://www.youtube.com/source/abc123"
|
||||
},
|
||||
update_attrs: %{
|
||||
original_url: "https://www.youtube.com/source/321xyz"
|
||||
},
|
||||
invalid_attrs: %{original_url: nil, media_profile_id: nil}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
describe "index" do
|
||||
test "lists all sources", %{conn: conn} do
|
||||
conn = get(conn, ~p"/media_sources/sources")
|
||||
assert html_response(conn, 200) =~ "Listing Sources"
|
||||
end
|
||||
end
|
||||
|
||||
describe "new source" do
|
||||
test "renders form", %{conn: conn} do
|
||||
conn = get(conn, ~p"/media_sources/sources/new")
|
||||
assert html_response(conn, 200) =~ "New Source"
|
||||
end
|
||||
end
|
||||
|
||||
describe "create source" do
|
||||
test "redirects to show when data is valid", %{conn: conn, create_attrs: create_attrs} do
|
||||
expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3)
|
||||
conn = post(conn, ~p"/media_sources/sources", source: create_attrs)
|
||||
|
||||
assert %{id: id} = redirected_params(conn)
|
||||
assert redirected_to(conn) == ~p"/media_sources/sources/#{id}"
|
||||
|
||||
conn = get(conn, ~p"/media_sources/sources/#{id}")
|
||||
assert html_response(conn, 200) =~ "Source #{id}"
|
||||
end
|
||||
|
||||
test "renders errors when data is invalid", %{conn: conn, invalid_attrs: invalid_attrs} do
|
||||
conn = post(conn, ~p"/media_sources/sources", source: invalid_attrs)
|
||||
assert html_response(conn, 200) =~ "New Source"
|
||||
end
|
||||
end
|
||||
|
||||
describe "edit source" do
|
||||
setup [:create_source]
|
||||
|
||||
test "renders form for editing chosen source", %{conn: conn, source: source} do
|
||||
conn = get(conn, ~p"/media_sources/sources/#{source}/edit")
|
||||
assert html_response(conn, 200) =~ "Edit Source"
|
||||
end
|
||||
end
|
||||
|
||||
describe "update source" do
|
||||
setup [:create_source]
|
||||
|
||||
test "redirects when data is valid", %{conn: conn, source: source, update_attrs: update_attrs} do
|
||||
expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3)
|
||||
|
||||
conn = put(conn, ~p"/media_sources/sources/#{source}", source: update_attrs)
|
||||
assert redirected_to(conn) == ~p"/media_sources/sources/#{source}"
|
||||
|
||||
conn = get(conn, ~p"/media_sources/sources/#{source}")
|
||||
assert html_response(conn, 200) =~ "https://www.youtube.com/source/321xyz"
|
||||
end
|
||||
|
||||
test "renders errors when data is invalid", %{
|
||||
conn: conn,
|
||||
source: source,
|
||||
invalid_attrs: invalid_attrs
|
||||
} do
|
||||
conn = put(conn, ~p"/media_sources/sources/#{source}", source: invalid_attrs)
|
||||
assert html_response(conn, 200) =~ "Edit Source"
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete source" do
|
||||
setup [:create_source]
|
||||
|
||||
test "deletes chosen source", %{conn: conn, source: source} do
|
||||
conn = delete(conn, ~p"/media_sources/sources/#{source}")
|
||||
assert redirected_to(conn) == ~p"/media_sources/sources"
|
||||
|
||||
assert_error_sent 404, fn ->
|
||||
get(conn, ~p"/media_sources/sources/#{source}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp create_source(_) do
|
||||
source = source_fixture()
|
||||
%{source: source}
|
||||
end
|
||||
|
||||
defp runner_function_mock(_url, _opts, _ot) do
|
||||
{
|
||||
:ok,
|
||||
Phoenix.json_library().encode!(%{
|
||||
channel: "some name",
|
||||
channel_id: "some_source_id_#{:rand.uniform(1_000_000)}"
|
||||
})
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -16,7 +16,7 @@ defmodule Pinchflat.MediaFixtures do
|
||||
media_id: Faker.String.base64(12),
|
||||
title: Faker.Commerce.product_name(),
|
||||
media_filepath: "/video/#{Faker.File.file_name(:video)}",
|
||||
channel_id: MediaSourceFixtures.channel_fixture().id
|
||||
source_id: MediaSourceFixtures.source_fixture().id
|
||||
})
|
||||
|> Pinchflat.Media.create_media_item()
|
||||
|
||||
|
||||
@@ -6,18 +6,19 @@ defmodule Pinchflat.MediaSourceFixtures do
|
||||
|
||||
alias Pinchflat.Repo
|
||||
alias Pinchflat.ProfilesFixtures
|
||||
alias Pinchflat.MediaSource.Channel
|
||||
alias Pinchflat.MediaSource.Source
|
||||
|
||||
@doc """
|
||||
Generate a channel.
|
||||
Generate a source.
|
||||
"""
|
||||
def channel_fixture(attrs \\ %{}) do
|
||||
{:ok, channel} =
|
||||
%Channel{}
|
||||
|> Channel.changeset(
|
||||
def source_fixture(attrs \\ %{}) do
|
||||
{:ok, source} =
|
||||
%Source{}
|
||||
|> Source.changeset(
|
||||
Enum.into(attrs, %{
|
||||
name: "Channel ##{:rand.uniform(1_000_000)}",
|
||||
channel_id: Base.encode16(:crypto.hash(:md5, "#{:rand.uniform(1_000_000)}")),
|
||||
name: "Source ##{:rand.uniform(1_000_000)}",
|
||||
collection_id: Base.encode16(:crypto.hash(:md5, "#{:rand.uniform(1_000_000)}")),
|
||||
collection_type: "channel",
|
||||
original_url: "https://www.youtube.com/channel/#{Faker.String.base64(12)}",
|
||||
media_profile_id: ProfilesFixtures.media_profile_fixture().id,
|
||||
index_frequency_minutes: 60
|
||||
@@ -25,6 +26,6 @@ defmodule Pinchflat.MediaSourceFixtures do
|
||||
)
|
||||
|> Repo.insert()
|
||||
|
||||
channel
|
||||
source
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,7 +14,7 @@ defmodule Pinchflat.TasksFixtures do
|
||||
{:ok, task} =
|
||||
attrs
|
||||
|> Enum.into(%{
|
||||
channel_id: MediaSourceFixtures.channel_fixture().id,
|
||||
source_id: MediaSourceFixtures.source_fixture().id,
|
||||
job_id: JobFixtures.job_fixture().id
|
||||
})
|
||||
|> Pinchflat.Tasks.create_task()
|
||||
|
||||
Reference in New Issue
Block a user