defmodule MusicBrainzTest do use ExUnit.Case, async: true import MusicBrainz.Fixtures.Release import MusicBrainz.Fixtures.ReleaseGroup alias MusicBrainz.ReleaseGroupSearchResult describe "search_release_group/2" do test "returns results with correct limit and offset" do results = release_group_search_results() expected_results = Enum.map(results["release-groups"], &ReleaseGroupSearchResult.from_api_response/1) Req.Test.stub(MusicBrainz.API, fn conn -> Req.Test.json(conn, results) end) assert {:ok, result} = MusicBrainz.search_release_group("Marillion", limit: 20, offset: 10) assert result.release_groups == expected_results assert result.total_count == 437 end end describe "search_release_by_barcode/1" do test "returns releases belonging to the same release group" do barcode = "5052205070023" releases = releases(:queen_greatest_hits) Req.Test.stub(MusicBrainz.API, fn conn -> Req.Test.json(conn, releases) end) assert {:ok, results} = MusicBrainz.search_release_by_barcode(barcode) assert Enum.all?(results, fn result -> result.release_group.id == "69ce61c8-127f-3809-95d8-62fdf3ae1347" && result.release_group.title == "Greatest Hits" end) end end describe "get_all_releases/1" do @release_group_id "ae504fd6-8498-463e-8d96-14f9e11d1863" defp release_page(count) do releases = for i <- 1..count do %{"id" => "rel-#{:erlang.unique_integer([:positive])}", "title" => "Release #{i}"} end %{"releases" => releases, "release-offset" => 0, "release-count" => count} end test "single-page response returns the whole list" do page = release_page(25) Req.Test.stub(MusicBrainz.API, fn conn -> conn = Plug.Conn.fetch_query_params(conn) assert conn.query_params["offset"] == "0" assert conn.query_params["limit"] == "100" Req.Test.json(conn, page) end) assert {:ok, releases} = MusicBrainz.get_all_releases(@release_group_id) assert releases == page["releases"] end test "multi-page response accumulates pages in order until a short page is returned" do full_page = release_page(100) tail_page = release_page(42) {:ok, agent} = Agent.start_link(fn -> [] end) Req.Test.stub(MusicBrainz.API, fn conn -> conn = Plug.Conn.fetch_query_params(conn) Agent.update(agent, fn calls -> calls ++ [conn.query_params["offset"]] end) case conn.query_params["offset"] do "0" -> Req.Test.json(conn, full_page) "100" -> Req.Test.json(conn, tail_page) end end) assert {:ok, releases} = MusicBrainz.get_all_releases(@release_group_id) assert length(releases) == 142 assert releases == full_page["releases"] ++ tail_page["releases"] assert Agent.get(agent, & &1) == ["0", "100"] end test "exact-boundary page (equal to limit) triggers an extra fetch that returns empty" do full_page = release_page(100) empty_page = %{"releases" => []} Req.Test.stub(MusicBrainz.API, fn conn -> conn = Plug.Conn.fetch_query_params(conn) case conn.query_params["offset"] do "0" -> Req.Test.json(conn, full_page) "100" -> Req.Test.json(conn, empty_page) end end) assert {:ok, releases} = MusicBrainz.get_all_releases(@release_group_id) assert length(releases) == 100 assert releases == full_page["releases"] end test "empty response returns an empty list" do Req.Test.stub(MusicBrainz.API, fn conn -> Req.Test.json(conn, %{"releases" => []}) end) assert {:ok, releases} = MusicBrainz.get_all_releases(@release_group_id) assert releases == [] end test "error on a later page is returned immediately" do full_page = release_page(100) Req.Test.stub(MusicBrainz.API, fn conn -> conn = Plug.Conn.fetch_query_params(conn) case conn.query_params["offset"] do "0" -> Req.Test.json(conn, full_page) "100" -> conn |> Plug.Conn.put_resp_content_type("application/json") |> Plug.Conn.send_resp(503, ~s({"error":"service unavailable"})) end end) assert {:error, %{"error" => "service unavailable"}} = MusicBrainz.get_all_releases(@release_group_id) end end end