From acda82fc10570d1de99de1074ee0372525da699f Mon Sep 17 00:00:00 2001 From: Moises Macia Date: Wed, 10 Jun 2026 23:48:35 +0000 Subject: [PATCH] add tests --- test/feed_reader/remote_session_test.exs | 107 +++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 test/feed_reader/remote_session_test.exs diff --git a/test/feed_reader/remote_session_test.exs b/test/feed_reader/remote_session_test.exs new file mode 100644 index 0000000..4d2a9d7 --- /dev/null +++ b/test/feed_reader/remote_session_test.exs @@ -0,0 +1,107 @@ +defmodule FeedReader.RemoteSessionTest do + use ExUnit.Case, async: false + + alias FeedReader.{Feed, Item, RemoteResult, Session} + + @xml ~s(RemoteFirstoneSecondtwo) + + test "streams remote events with fetch metadata and removes the file after completion" do + assert {:ok, %Session{fetch: fetch, events: events, resource: %{path: path}}} = + stream(@xml) + + assert fetch.final_url == "https://example.com/final.xml" + assert fetch.etag == "\"v1\"" + assert File.exists?(path) + + assert [ + {:feed, %Feed{title: "Remote", feed_url: "https://example.com/final.xml"}}, + {:item, %Item{uuid: "one"}}, + {:item, %Item{uuid: "two"}} + ] = Enum.to_list(events) + + refute File.exists?(path) + end + + test "closes an unstarted or partially consumed session idempotently" do + assert {:ok, %Session{resource: %{path: path}} = session} = stream(@xml) + assert :ok = FeedReader.close(session) + assert :ok = FeedReader.close(session) + refute File.exists?(path) + + assert {:ok, %Session{events: events2, resource: %{path: path2}}} = stream(@xml) + assert [{:feed, %Feed{}}] = events2 |> Stream.take(1) |> Enum.to_list() + refute File.exists?(path2) + end + + test "collects remote feeds within the required finite item limit" do + assert {:error, {:invalid_option, :max_items}} = fetch_and_parse(@xml, []) + refute_received {:transport_request, _url} + + assert {:ok, %RemoteResult{feed: %Feed{title: "Remote"}, items: items, fetch: fetch}} = + fetch_and_parse(@xml, max_items: 2) + + assert [%Item{uuid: "one"}, %Item{uuid: "two"}] = items + assert fetch.status == 200 + + before = download_files() + assert {:error, {:max_items_exceeded, 1}} = fetch_and_parse(@xml, max_items: 1) + assert download_files() == before + + assert {:error, _reason} = fetch_and_parse(@xml <> "", format: :invalid_format) + assert download_files() == before + end + + test "covers default options and closing a local session" do + assert {:error, :invalid_url} = FeedReader.stream(:invalid) + + assert {:error, {:invalid_option, :max_items}} = + FeedReader.fetch_and_parse("https://example.com/feed.xml") + + assert :ok = FeedReader.close(%Session{}) + end + + defp stream(xml, opts \\ []) do + FeedReader.stream("https://example.com/feed.xml", request_opts(xml, opts)) + end + + defp fetch_and_parse(xml, opts) do + request = request_opts(xml, opts) + FeedReader.fetch_and_parse("https://example.com/feed.xml", request) + end + + defp request_opts(xml, opts) do + response = Keyword.get(opts, :response, response([xml], [{"ETag", "\"v1\""}])) + + [ + http_client: FeedReader.TestSupport.TransportClient, + response: response, + test_pid: self() + ] ++ Keyword.delete(opts, :response) + end + + defp response(body, headers, status \\ 200), + do: %{ + status: status, + headers: headers, + final_url: "https://example.com/final.xml", + body: body + } + + defp checksum(xml), do: Base.encode16(:crypto.hash(:md5, xml), case: :lower) + + defp download_files do + Path.join(System.tmp_dir!(), "feed_reader-download-*.xml") |> Path.wildcard() + end +end