diff --git a/apps/transport/lib/transport/gbfs_metadata.ex b/apps/transport/lib/transport/gbfs_metadata.ex index 9061797330..194b3f15fa 100644 --- a/apps/transport/lib/transport/gbfs_metadata.ex +++ b/apps/transport/lib/transport/gbfs_metadata.ex @@ -41,7 +41,7 @@ defmodule Transport.GBFSMetadata do """ @impl Transport.GBFSMetadata.Wrapper def compute_feed_metadata(url) do - {:ok, %HTTPoison.Response{status_code: 200, body: body}} = http_client().get(url) + {:ok, %HTTPoison.Response{status_code: 200, body: body}} = cached_http_get(url) {:ok, json} = Jason.decode(body) # we compute the feed delay before the rest for accuracy @@ -122,7 +122,7 @@ defmodule Transport.GBFSMetadata do defp feed_ttl(value) when is_integer(value) and value >= 0, do: value defp feed_ttl(feed_url) when is_binary(feed_url) do - with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- http_client().get(feed_url), + with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- cached_http_get(feed_url), {:ok, json} <- Jason.decode(body) do json["ttl"] else @@ -196,7 +196,7 @@ defmodule Transport.GBFSMetadata do feed_url = feed_url_by_name(payload, :station_status) with {:feed_exists, true} <- {:feed_exists, not is_nil(feed_url)}, - {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- http_client().get(feed_url), + {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- cached_http_get(feed_url), {:ok, json} <- Jason.decode(body) do stations = Enum.reject(json["data"]["stations"], &unrealistic_station_data?/1) @@ -224,7 +224,7 @@ defmodule Transport.GBFSMetadata do feed_url = feed_url_by_name(payload, :vehicle_status) with {:feed_exists, true} <- {:feed_exists, not is_nil(feed_url)}, - {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- http_client().get(feed_url), + {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- cached_http_get(feed_url), {:ok, json} <- Jason.decode(body) do vehicles = json["data"]["vehicles"] || json["data"]["bikes"] nb_vehicles = Enum.count(vehicles) @@ -274,7 +274,7 @@ defmodule Transport.GBFSMetadata do feed_url = feed_url_by_name(payload, :system_information) with {:feed_exists, true} <- {:feed_exists, not is_nil(feed_url)}, - {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- http_client().get(feed_url), + {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- cached_http_get(feed_url), {:ok, json} <- Jason.decode(body) do transform_localized_strings(json["data"]) else @@ -320,7 +320,7 @@ defmodule Transport.GBFSMetadata do # > If this file is not included, then all vehicles in the feed are assumed to be non-motorized bicycles. ["bicycle"] else - with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- http_client().get(feed_url), + with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- cached_http_get(feed_url), {:ok, json} <- Jason.decode(body) do json["data"]["vehicle_types"] |> Enum.map(& &1["form_factor"]) |> Enum.uniq() else @@ -335,7 +335,7 @@ defmodule Transport.GBFSMetadata do else feed_url = feed_url_by_name(payload, :system_information) - with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- http_client().get(feed_url), + with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- cached_http_get(feed_url), {:ok, json} <- Jason.decode(body) do get_in(json, ["data", "languages"]) else @@ -351,7 +351,7 @@ defmodule Transport.GBFSMetadata do if is_nil(versions_url) do [Map.get(payload, "version", "1.0")] else - with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- http_client().get(versions_url), + with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- cached_http_get(versions_url), {:ok, json} <- Jason.decode(body) do json["data"]["versions"] |> Enum.map(& &1["version"]) |> Enum.sort(:desc) else @@ -427,5 +427,13 @@ defmodule Transport.GBFSMetadata do # https://github.com/MobilityData/gbfs/blob/v1.1/gbfs.md#output-format defp before_v3?(%{}), do: true + defp cached_http_get(url) do + Transport.Cache.fetch( + "#{__MODULE__}::http_get::#{url}", + fn -> http_client().get(url) end, + :timer.seconds(30) + ) + end + defp http_client, do: Transport.Shared.Wrapper.HTTPoison.impl() end diff --git a/apps/transport/test/transport/gbfs_metadata_test.exs b/apps/transport/test/transport/gbfs_metadata_test.exs index 4e28e66c3e..fe3c7d73e5 100644 --- a/apps/transport/test/transport/gbfs_metadata_test.exs +++ b/apps/transport/test/transport/gbfs_metadata_test.exs @@ -1,5 +1,6 @@ defmodule Transport.GBFSMetadataTest do - use ExUnit.Case, async: true + # async: false is required because we use real in-memory caching in these tests + use ExUnit.Case, async: false import Mox import Transport.GBFSMetadata import ExUnit.CaptureLog @@ -9,8 +10,20 @@ defmodule Transport.GBFSMetadataTest do @gbfs_url "https://example.com/gbfs.json" + setup :set_mox_global setup :verify_on_exit! + setup do + # Use a real in-memory cache for these tests to test the caching mecanism + old_value = Application.fetch_env!(:transport, :cache_impl) + Application.put_env(:transport, :cache_impl, Transport.Cache.Cachex) + + on_exit(fn -> + Application.put_env(:transport, :cache_impl, old_value) + Cachex.reset(Transport.Cache.Cachex.cache_name()) + end) + end + describe "Compute GBFS metadata for a feed" do test "for a stations feed with a single version" do setup_feeds([:gbfs, :system_information, :station_information, :station_status]) @@ -60,8 +73,7 @@ defmodule Transport.GBFSMetadataTest do :system_information, :vehicle_types, :free_bike_status, - :station_status, - :free_bike_status + :station_status ]) setup_validation_result(