From 7346cd2687379f1648e3bc9c491d7e0e8286e95b Mon Sep 17 00:00:00 2001 From: Cristen Jones Date: Mon, 3 Aug 2026 17:34:09 -0400 Subject: [PATCH] refactor(ScheduleController): remove unused predictions One could argue they were used for the Green line's vehicle tooltips, except there's another code path it goes through which also populates vehicle tooltip. For the vehicle maps the result seems pretty much the same. --- lib/dotcom_web/controllers/schedule/green.ex | 24 +- .../controllers/schedule/predictions.ex | 124 ------- .../controllers/schedule/vehicle_tooltips.ex | 5 +- lib/vehicle_helpers.ex | 37 +- test/dotcom/lib/vehicle_helpers_test.exs | 94 +---- .../controllers/schedule/green_test.exs | 77 ---- .../controllers/schedule/predictions_test.exs | 337 ------------------ 7 files changed, 24 insertions(+), 674 deletions(-) delete mode 100644 lib/dotcom_web/controllers/schedule/predictions.ex delete mode 100644 test/dotcom_web/controllers/schedule/predictions_test.exs diff --git a/lib/dotcom_web/controllers/schedule/green.ex b/lib/dotcom_web/controllers/schedule/green.ex index 766407dcb1..7a279c77fd 100644 --- a/lib/dotcom_web/controllers/schedule/green.ex +++ b/lib/dotcom_web/controllers/schedule/green.ex @@ -15,7 +15,7 @@ defmodule DotcomWeb.ScheduleController.Green do import DotcomWeb.Schedule.Line, only: [line_direction: 2] import DotcomWeb.Schedule.RouteBreadcrumbs, only: [assign_breadcrumbs: 2] - alias DotcomWeb.Schedule.{Predictions, VehicleLocations} + alias DotcomWeb.Schedule.VehicleLocations alias DotcomWeb.ScheduleController.LineController alias DotcomWeb.ScheduleView @@ -27,7 +27,6 @@ defmodule DotcomWeb.ScheduleController.Green do plug(:assign_next_holidays) plug(:stops_on_routes) plug(:vehicle_locations) - plug(:predictions) plug(DotcomWeb.ScheduleController.VehicleTooltips) plug(:assign_breadcrumbs) plug(DotcomWeb.ScheduleController.ScheduleError) @@ -76,27 +75,6 @@ defmodule DotcomWeb.ScheduleController.Green do assign(conn, :stops_on_routes, GreenLine.stops_on_routes(direction_id, date)) end - def predictions(conn, _opts) do - {predictions, vehicle_predictions} = - conn - |> conn_with_branches - |> Task.async_stream( - fn branch_conn -> - Predictions.all_predictions(branch_conn) - end, - timeout: @task_timeout - ) - |> Enum.reduce({[], []}, fn {:ok, branch_conn}, - {acc_predictions, acc_vehicle_predictions} -> - {branch_conn.assigns.predictions ++ acc_predictions, - branch_conn.assigns.vehicle_predictions ++ acc_vehicle_predictions} - end) - - conn - |> assign(:predictions, predictions) - |> assign(:vehicle_predictions, vehicle_predictions) - end - def vehicle_locations(conn, opts) do vehicle_locations = conn diff --git a/lib/dotcom_web/controllers/schedule/predictions.ex b/lib/dotcom_web/controllers/schedule/predictions.ex deleted file mode 100644 index bb8404097b..0000000000 --- a/lib/dotcom_web/controllers/schedule/predictions.ex +++ /dev/null @@ -1,124 +0,0 @@ -defmodule DotcomWeb.Schedule.Predictions do - @moduledoc """ - - Assigns predictions based on the currently selected route/stop/direction. - - """ - - require Logger - - import Plug.Conn - - alias Predictions.Prediction - alias Util.AsyncAssign - - @predictions_repo Application.compile_env!(:dotcom, :repo_modules)[:predictions] - - def all_predictions(conn) do - if should_fetch_predictions?(conn) do - predictions_task = fn -> predictions(conn) end - vehicle_predictions_task = fn -> vehicle_predictions(conn) end - - conn - |> AsyncAssign.async_assign_default(:predictions, predictions_task, []) - |> AsyncAssign.async_assign_default(:vehicle_predictions, vehicle_predictions_task, []) - |> AsyncAssign.await_assign_all_default(__MODULE__) - else - conn - |> assign(:predictions, []) - |> assign(:vehicle_predictions, []) - end - end - - @spec should_fetch_predictions?(Plug.Conn.t()) :: boolean - @doc "We only fetch predictions if we selected an origin and the date is today." - def should_fetch_predictions?(%{assigns: %{origin: nil}}) do - false - end - - def should_fetch_predictions?(%{assigns: assigns}) do - Date.compare(assigns.date, Util.service_date(assigns.date_time)) == :eq - end - - @spec predictions(Plug.Conn.t()) :: [Prediction.t()] - defp predictions(%{ - assigns: %{ - origin: origin, - destination: destination, - route: %{id: route_id}, - direction_id: direction_id - } - }) - when not is_nil(origin) do - destination_id = if destination, do: Map.get(destination, :id) - - opts = - if destination_id do - [route: route_id] - else - [route: route_id, direction_id: direction_id] - end - - @predictions_repo.all(opts) - |> case do - {:error, error} -> - Logger.error("predictions for opts #{inspect(opts)}: #{inspect(error)}") - - [] - - list -> - list - |> Enum.filter(fn prediction -> - prediction.stop && prediction.stop.id in [origin.id, destination_id] - end) - |> filter_stop_at_origin(origin.id) - |> filter_missing_trip - end - end - - defp predictions(_conn) do - [] - end - - @spec filter_stop_at_origin([Prediction.t()], Stops.Stop.id_t()) :: [Prediction.t()] - defp filter_stop_at_origin(predictions, origin_id) do - predictions - |> Enum.reject(fn - %Prediction{time: nil} -> false - %Prediction{stop: %{id: ^origin_id}, departing?: false} -> true - %Prediction{} -> false - end) - end - - @spec filter_missing_trip([Prediction.t()]) :: [Prediction.t()] - defp filter_missing_trip(predictions) do - Enum.filter(predictions, fn pred -> - pred.trip != nil || pred.status != nil - end) - end - - @spec vehicle_predictions(Plug.Conn.t()) :: [Prediction.t()] - defp vehicle_predictions(%{assigns: %{vehicle_locations: vehicle_locations}}) do - {trip_ids, stop_ids} = - vehicle_locations - |> Map.keys() - |> Enum.unzip() - - trip_ids = trip_ids |> Enum.reject(&is_nil/1) |> Enum.join(",") - - case @predictions_repo.all(trip: trip_ids) do - {:error, error} -> - Logger.error("predictions for trips #{inspect(trip_ids)}: #{inspect(error)}") - - [] - - list -> - list - |> Enum.filter(&(&1.stop && &1.stop.id in stop_ids)) - end - end - - defp vehicle_predictions(_conn) do - [] - end -end diff --git a/lib/dotcom_web/controllers/schedule/vehicle_tooltips.ex b/lib/dotcom_web/controllers/schedule/vehicle_tooltips.ex index f7c78bb5f9..6a9bce71bf 100644 --- a/lib/dotcom_web/controllers/schedule/vehicle_tooltips.ex +++ b/lib/dotcom_web/controllers/schedule/vehicle_tooltips.ex @@ -1,6 +1,6 @@ defmodule DotcomWeb.ScheduleController.VehicleTooltips do @moduledoc """ - Assigns :vehicle_tooltips based on previously requested :route, :vehicle_locations and :vehicle_predictions. + Assigns :vehicle_tooltips based on previously requested :route, :vehicle_locations """ import Plug.Conn, only: [assign: 3] @@ -21,8 +21,7 @@ defmodule DotcomWeb.ScheduleController.VehicleTooltips do :vehicle_tooltips, VehicleHelpers.build_tooltip_index( conn.assigns.route, - conn.assigns.vehicle_locations, - conn.assigns.vehicle_predictions + conn.assigns.vehicle_locations ) ) end diff --git a/lib/vehicle_helpers.ex b/lib/vehicle_helpers.ex index 7177e196a9..5da76bc4a3 100644 --- a/lib/vehicle_helpers.ex +++ b/lib/vehicle_helpers.ex @@ -14,6 +14,7 @@ defmodule VehicleHelpers do alias Schedules.Trip alias Vehicles.Vehicle + @schedules_repo Application.compile_env!(:dotcom, :repo_modules)[:schedules] @stops_repo Application.compile_env!(:dotcom, :repo_modules)[:stops] @type tooltip_index_key :: {Trip.id_t() | nil, Stop.id_t()} | Stop.id_t() @@ -27,32 +28,19 @@ defmodule VehicleHelpers do construct a convenient map that can be used in views / templates to determine if a tooltip is available and to fetch all of the required data """ - @spec build_tooltip_index(Route.t(), VehicleLocations.t(), [Prediction.t()]) :: tooltip_index - def build_tooltip_index(route, vehicle_locations, vehicle_predictions) do - indexed_predictions = index_vehicle_predictions(vehicle_predictions) - + @spec build_tooltip_index(Route.t(), VehicleLocations.t()) :: tooltip_index + def build_tooltip_index(route, vehicle_locations) do vehicle_locations |> Stream.reject(fn {{_trip_id, stop_id}, _status} -> is_nil(stop_id) end) |> Enum.reduce(%{}, fn vehicle_location, output -> {{trip_id, stop_id}, vehicle} = vehicle_location - - {prediction, trip} = - if trip_id do - { - prediction_for_stop(indexed_predictions, trip_id, vehicle.stop_id), - Schedules.Repo.trip(trip_id) - } - else - {nil, nil} - end - stop_name = @stops_repo.get(vehicle.stop_id) |> stop_name() tooltip = %VehicleTooltip{ vehicle: vehicle, - prediction: prediction, + prediction: nil, stop_name: stop_name, - trip: trip, + trip: if(trip_id, do: @schedules_repo.trip(trip_id)), route: route } @@ -62,21 +50,6 @@ defmodule VehicleHelpers do end) end - @spec prediction_for_stop(VehicleLocations.t(), String.t(), String.t()) :: Prediction.t() | nil - defp prediction_for_stop(vehicle_predictions, trip_id, stop_id) do - Map.get(vehicle_predictions, {trip_id, stop_id}) - end - - @spec index_vehicle_predictions([Prediction.t()]) :: %{ - {String.t(), String.t()} => Prediction.t() - } - defp index_vehicle_predictions(predictions) do - predictions - |> Stream.filter(&(&1.trip && &1.stop)) - |> Stream.map(&{{&1.trip.id, &1.stop.id}, &1}) - |> Enum.into(Map.new()) - end - @spec stop_name(Stops.Stop.t() | nil) :: String.t() defp stop_name(nil), do: "" defp stop_name(stop), do: stop.name diff --git a/test/dotcom/lib/vehicle_helpers_test.exs b/test/dotcom/lib/vehicle_helpers_test.exs index 272a1cef16..7bbb3ce924 100644 --- a/test/dotcom/lib/vehicle_helpers_test.exs +++ b/test/dotcom/lib/vehicle_helpers_test.exs @@ -25,15 +25,13 @@ defmodule Dotcom.VehicleHelpersTest do } } - @predictions [ - %Predictions.Prediction{ - departing?: true, - time: ~N[2018-05-01T11:00:00], - status: "On Time", - trip: @trip, - stop: @station - } - ] + @prediction %Predictions.Prediction{ + departing?: true, + time: ~N[2018-05-01T11:00:00], + status: "On Time", + trip: @trip, + stop: @station + } setup :verify_on_exit! @@ -42,29 +40,20 @@ defmodule Dotcom.VehicleHelpersTest do @station end) - stub(MBTA.Api.Mock, :get_json, fn "/trips/" <> id, _ -> - trip = - Test.Support.Factories.MBTA.Api.build(:trip_item, - id: id, - attributes: %{ - "name" => @trip.name, - "headsign" => @trip.headsign - } - ) - - %JsonApi{links: %{}, data: [trip]} + stub(Schedules.Repo.Mock, :trip, fn _ -> + @trip end) :ok end setup do - tooltips = build_tooltip_index(@route, @locations, @predictions) + tooltips = build_tooltip_index(@route, @locations) {:ok, tooltips: tooltips, tooltip_base: tooltips[@station.id]} end - describe "build_tooltip_index/3" do + describe "build_tooltip_index/2" do test "verify the Vehicle tooltip data", %{tooltips: tooltips, tooltip_base: tooltip_base} do assert length(Map.keys(tooltips)) == 2 assert Map.has_key?(tooltips, {"CR-554466-501", "place-sstat"}) @@ -72,13 +61,12 @@ defmodule Dotcom.VehicleHelpersTest do assert tooltip_base.route.type == 2 assert tooltip_base.trip.name == "501" assert tooltip_base.trip.headsign == "Worcester" - assert tooltip_base.prediction.status == "On Time" assert tooltip_base.vehicle.status == :stopped end test "it does not return a tooltip if a vehicle has a null stop_id" do null_location = %{{"trip-1", nil} => %Vehicles.Vehicle{}} - tooltips = build_tooltip_index(@route, Enum.concat(@locations, null_location), @predictions) + tooltips = build_tooltip_index(@route, Enum.concat(@locations, null_location)) assert length(Map.keys(tooltips)) == 2 assert Map.has_key?(tooltips, {"CR-554466-501", "place-sstat"}) @@ -89,13 +77,12 @@ defmodule Dotcom.VehicleHelpersTest do assert tooltip_base.route.type == 2 assert tooltip_base.trip.name == "501" assert tooltip_base.trip.headsign == "Worcester" - assert tooltip_base.prediction.status == "On Time" assert tooltip_base.vehicle.status == :stopped end test "it does return a tooltip if a vehicle has a null trip_id" do null_trip = %{{nil, "place-sstat"} => %Vehicles.Vehicle{stop_id: ""}} - tooltips = build_tooltip_index(@route, null_trip, []) + tooltips = build_tooltip_index(@route, null_trip) tooltip_base = tooltips["place-sstat"] assert length(Map.keys(tooltips)) == 2 assert Map.has_key?(tooltips, {nil, "place-sstat"}) @@ -105,39 +92,6 @@ defmodule Dotcom.VehicleHelpersTest do assert tooltip_base.prediction == nil assert tooltip_base.vehicle == %Vehicles.Vehicle{stop_id: ""} end - - test "it uses the prediction corresponding to the vehicle's current stop" do - locations = %{ - {"trip_1", "stop_1"} => %Vehicles.Vehicle{ - stop_id: "stop_1", - trip_id: "trip_1" - } - } - - predictions = [ - %Predictions.Prediction{ - departing?: false, - time: ~N[2017-01-01T11:10:00], - status: "On Time", - trip: %Schedules.Trip{id: "trip_1"}, - stop: %Stops.Stop{id: "stop_2"} - }, - correct_prediction = %Predictions.Prediction{ - departing?: true, - time: ~N[2017-01-01T11:00:00], - status: "On Time", - trip: %Schedules.Trip{id: "trip_1"}, - stop: %Stops.Stop{id: "stop_1"} - } - ] - - route = %Routes.Route{type: 2} - - tooltips = build_tooltip_index(route, locations, predictions) - tooltip = tooltips[{"trip_1", "stop_1"}] - - assert tooltip.prediction == correct_prediction - end end describe "tooltip/1" do @@ -146,7 +100,7 @@ defmodule Dotcom.VehicleHelpersTest do } do tooltip = %{ tooltip_base - | prediction: %{tooltip_base.prediction | status: "Now Boarding", track: "4"} + | prediction: %{@prediction | status: "Now Boarding", track: "4"} } assert tooltip(tooltip) =~ "now boarding on track 4" @@ -155,7 +109,7 @@ defmodule Dotcom.VehicleHelpersTest do test "when a prediction does not have a track, gives nothing", %{tooltip_base: tooltip_base} do tooltip = %{ tooltip_base - | prediction: %{tooltip_base.prediction | status: "Now Boarding", track: nil} + | prediction: %{@prediction | status: "Now Boarding", track: nil} } refute tooltip(tooltip) =~ "now boarding" @@ -166,7 +120,7 @@ defmodule Dotcom.VehicleHelpersTest do } do tooltip = %{ tooltip_base - | prediction: %{tooltip_base.prediction | status: nil, time: nil} + | prediction: %{@prediction | status: nil, time: nil} } assert tooltip(tooltip) =~ "South Station" @@ -230,20 +184,4 @@ defmodule Dotcom.VehicleHelpersTest do assert actual =~ "has left South Station, departed on track 4" end end - - describe "prediction_for_stop/2" do - test "do not crash if vehicle prediction does not contain a trip" do - predictions = [ - %Predictions.Prediction{ - departing?: true, - time: ~N[2017-01-01T11:00:00], - status: "On Time" - } - ] - - tooltips = build_tooltip_index(@route, @locations, predictions) - tooltip = tooltips["place-sstat"] - assert tooltip(tooltip) =~ "train 501 has arrived" - end - end end diff --git a/test/dotcom_web/controllers/schedule/green_test.exs b/test/dotcom_web/controllers/schedule/green_test.exs index 3f47592315..9f4378cd21 100644 --- a/test/dotcom_web/controllers/schedule/green_test.exs +++ b/test/dotcom_web/controllers/schedule/green_test.exs @@ -62,83 +62,6 @@ defmodule DotcomWeb.ScheduleController.GreenTest do assert conn.assigns.meta_description end - describe "predictions" do - test "assigns predictions and vehicle_predictions for all branches", %{conn: conn} do - conn = - conn - |> assign(:date, ~D[2017-01-01]) - |> assign(:date_time, ~N[2017-01-01T12:00:00]) - |> assign(:origin, %Stops.Stop{id: "place-north"}) - |> assign(:destination, nil) - |> assign(:direction_id, 0) - |> assign(:route, @green_line) - |> assign(:vehicle_locations, %{ - {"trip_1", "stop_1"} => %Vehicles.Vehicle{}, - {"trip_2", "stop_3"} => %Vehicles.Vehicle{} - }) - |> predictions( - predictions_fn: fn params -> - case Enum.into(params, Map.new()) do - # vehicle predictions - %{trip: trip_ids} -> - Enum.map( - cartesian_product(trip_ids, "stop_1,stop_3"), - fn {trip_id, stop_id} -> - %Predictions.Prediction{ - id: "vehicle_predictions", - trip: %Schedules.Trip{id: trip_id}, - stop: %Stops.Stop{id: stop_id} - } - end - ) - - # predictions - value - when value in [ - %{direction_id: 0, route: "Green-E"}, - %{direction_id: 0, route: "Green-D"}, - %{direction_id: 0, route: "Green-C"}, - %{direction_id: 0, route: "Green-B"} - ] -> - [ - %Predictions.Prediction{ - id: "predictions", - trip: 1234, - route: %Routes.Route{id: value[:route]}, - stop: %Stops.Stop{id: "place-north"}, - departing?: true - } - ] - end - end - ) - - assert Enum.map(conn.assigns.predictions, & &1.route.id) == GreenLine.branch_ids() - assert Enum.all?(conn.assigns.predictions, &(&1.id == "predictions")) - - vehicle_prediction_ids = - conn.assigns.vehicle_predictions - |> Enum.map(&{&1.trip.id, &1.stop.id}) - |> Enum.sort() - - assert vehicle_prediction_ids == [ - {"trip_1", "stop_1"}, - {"trip_1", "stop_3"}, - {"trip_2", "stop_1"}, - {"trip_2", "stop_3"} - ] - - assert Enum.all?(conn.assigns.vehicle_predictions, &(&1.id == "vehicle_predictions")) - end - - defp cartesian_product(xs, ys) do - for x <- String.split(xs, ","), - y <- String.split(ys, ",") do - {x, y} - end - end - end - test "assigns vehicle locations for all branches", %{conn: conn} do conn = conn diff --git a/test/dotcom_web/controllers/schedule/predictions_test.exs b/test/dotcom_web/controllers/schedule/predictions_test.exs deleted file mode 100644 index fa8fae6b4b..0000000000 --- a/test/dotcom_web/controllers/schedule/predictions_test.exs +++ /dev/null @@ -1,337 +0,0 @@ -defmodule DotcomWeb.Schedule.PredictionsTest do - use DotcomWeb.ConnCase, async: true - - import DotcomWeb.Schedule.Predictions - import Mox - import Test.Support.Factories.Predictions.Prediction - - setup %{conn: conn} do - cache = Application.get_env(:dotcom, :cache) - cache.flush() - - conn = - conn - |> assign(:date, ~D[2017-01-01]) - |> assign(:date_time, ~N[2017-01-01T12:00:00]) - - {:ok, %{conn: conn}} - end - - describe "all_predictions/1" do - test "when given a date that isn't the service date, assigns no predictions", %{conn: conn} do - conn = - conn - |> assign(:date, ~D[2016-12-31]) - |> assign(:origin, Faker.Pokemon.location()) - |> all_predictions() - - assert conn.assigns[:predictions] == [] - assert conn.assigns[:vehicle_predictions] == [] - end - - test "when there is no origin, assigns no predictions", %{conn: conn} do - conn = - conn - |> assign(:origin, nil) - |> all_predictions() - - assert conn.assigns[:predictions] == [] - assert conn.assigns[:vehicle_predictions] == [] - end - - test "assigns predictions for a route, stop, and direction ID", %{conn: conn} do - route_id = "#{Faker.Util.digit()}" - direction_id = "#{Faker.Util.digit()}" - - expect(Predictions.Repo.Mock, :all, fn [route: ^route_id, direction_id: ^direction_id] -> - build_list(1, :prediction, %{}) - end) - - conn = - conn - |> assign(:origin, %Stops.Stop{id: Faker.Pokemon.location()}) - |> assign(:destination, nil) - |> assign(:route, %{id: route_id}) - |> assign(:direction_id, direction_id) - |> all_predictions() - - assert conn.assigns[:predictions] == [] - end - - test "ignores predictions which have the origin as their destination", %{conn: conn} do - stop_id = Faker.Pokemon.location() - trip_id = Faker.random_between(1000, 9999) - - expect(Predictions.Repo.Mock, :all, fn _ -> - build_list(1, :prediction, %{ - time: ~N[2017-01-01T00:00:00], - stop: %Stops.Stop{id: stop_id}, - trip: trip_id, - departing?: false - }) - end) - - conn = - conn - |> assign(:origin, %Stops.Stop{id: stop_id}) - |> assign(:destination, nil) - |> assign(:route, %{id: "#{Faker.Util.digit()}"}) - |> assign(:direction_id, "#{Faker.Util.digit()}") - |> all_predictions() - - assert conn.assigns.predictions == [] - end - - test "does not ignore predictions which have a trip id but not status", %{conn: conn} do - stop_id = Faker.Pokemon.location() - - prediction = - build(:prediction, %{ - time: ~N[2017-01-01T00:00:00], - stop: %Stops.Stop{id: stop_id}, - trip: Faker.random_between(1000, 9999), - departing?: true - }) - - expect(Predictions.Repo.Mock, :all, fn _ -> - [prediction] - end) - - conn = - conn - |> assign(:origin, %Stops.Stop{id: stop_id}) - |> assign(:destination, nil) - |> assign(:route, %{id: "#{Faker.Util.digit()}"}) - |> assign(:direction_id, "#{Faker.Util.digit()}") - |> all_predictions() - - assert conn.assigns.predictions == [prediction] - end - - test "does not ignore predictions which have a status but not a trip id", %{conn: conn} do - stop_id = Faker.Pokemon.location() - - prediction = - build(:prediction, %{ - time: ~N[2017-01-01T00:00:00], - stop: %Stops.Stop{id: stop_id}, - status: "On Time", - trip: nil, - departing?: true - }) - - expect(Predictions.Repo.Mock, :all, fn _ -> - [prediction] - end) - - conn = - conn - |> assign(:origin, %Stops.Stop{id: stop_id}) - |> assign(:destination, nil) - |> assign(:route, %{id: "#{Faker.Util.digit()}"}) - |> assign(:direction_id, "#{Faker.Util.digit()}") - |> all_predictions() - - assert conn.assigns.predictions == [prediction] - end - - test "ignores predictions which do not have a trip id or a status", %{conn: conn} do - stop_id = Faker.Pokemon.location() - - prediction = - build(:prediction, %{ - time: ~N[2017-01-01T00:00:00], - stop: %Stops.Stop{id: stop_id}, - status: nil, - trip: nil, - departing?: true - }) - - expect(Predictions.Repo.Mock, :all, fn _ -> - [prediction] - end) - - conn = - conn - |> assign(:origin, %Stops.Stop{id: stop_id}) - |> assign(:destination, nil) - |> assign(:route, %{id: "#{Faker.Util.digit()}"}) - |> assign(:direction_id, "#{Faker.Util.digit()}") - |> all_predictions() - - assert conn.assigns.predictions == [] - end - - test "keeps predictions without a time", %{conn: conn} do - stop_id = Faker.Pokemon.location() - - prediction = - build(:prediction, %{ - stop: %Stops.Stop{id: stop_id}, - trip: Faker.random_between(1000, 9999), - status: "", - departing?: true - }) - - expect(Predictions.Repo.Mock, :all, fn _ -> - [prediction] - end) - - conn = - conn - |> assign(:origin, %Stops.Stop{id: stop_id}) - |> assign(:destination, nil) - |> assign(:route, %{id: "#{Faker.Util.digit()}"}) - |> assign(:direction_id, "#{Faker.Util.digit()}") - |> all_predictions() - - assert conn.assigns.predictions == [prediction] - end - - test "otherwise, assigns no predictions", %{conn: conn} do - expect(Predictions.Repo.Mock, :all, fn _ -> - [] - end) - - conn = - conn - |> all_predictions() - - assert conn.assigns[:predictions] == [] - end - - test "destination predictions are assigned if destination is assigned", %{conn: conn} do - route_id = "#{Faker.Util.digit()}" - - expect(Predictions.Repo.Mock, :all, fn [route: ^route_id] -> - build_list(1, :prediction, %{}) - end) - - conn = - conn - |> assign(:origin, %Stops.Stop{id: Faker.Pokemon.location()}) - |> assign(:destination, %Stops.Stop{id: Faker.Pokemon.location()}) - |> assign(:route, %{id: route_id}) - |> assign(:direction_id, "#{Faker.Util.digit()}") - |> all_predictions() - - assert conn.assigns[:predictions] == [] - end - - @tag :flaky - test "assigns a list containing predictions for every stop with a vehicle at it", %{ - conn: conn - } do - stop_id_1 = Faker.Pokemon.location() - stop_id_2 = Faker.Pokemon.location() - route_id = "#{Faker.Util.digit()}" - trip_id_1 = "#{Faker.Internet.slug()}" - trip_id_2 = "#{Faker.Internet.slug()}" - - vehicle_locations = %{ - {trip_id_1, stop_id_1} => %Vehicles.Vehicle{ - trip_id: trip_id_1, - stop_id: stop_id_1, - status: :incoming - }, - {trip_id_2, stop_id_2} => %Vehicles.Vehicle{ - trip_id: trip_id_2, - stop_id: stop_id_2, - status: :stopped - } - } - - prediction_1 = build(:prediction, %{stop: %Stops.Stop{id: stop_id_1}}) - prediction_2 = build(:prediction, %{stop: %Stops.Stop{id: stop_id_2}}) - - trip_id_match = Enum.join(Enum.sort([trip_id_1, trip_id_2]), ",") - - Predictions.Repo.Mock - |> expect(:all, fn arg -> - assert arg[:route] == route_id - [] - end) - |> expect(:all, fn arg -> - assert arg[:trip] == trip_id_match - # we transform the data into this form so that we only need to make one repo call - [prediction_1, prediction_2] - end) - - conn = - conn - |> assign(:origin, %Stops.Stop{id: Faker.Pokemon.location()}) - |> assign(:destination, %Stops.Stop{id: Faker.Pokemon.location()}) - |> assign(:route, %{id: route_id}) - |> assign(:direction_id, "#{Faker.Util.digit()}") - |> assign(:vehicle_locations, vehicle_locations) - |> all_predictions() - - assert conn.assigns.vehicle_predictions == [ - prediction_1, - prediction_2 - ] - end - - @tag :flaky - test "does not make duplicate requests for vehicles at the same stop", %{conn: conn} do - stop_id_1 = Faker.Pokemon.location() - route_id = "#{Faker.Util.digit()}" - trip_id_1 = "#{Faker.Internet.slug()}" - trip_id_2 = "#{Faker.Internet.slug()}" - - vehicle_locations = %{ - {trip_id_1, stop_id_1} => %Vehicles.Vehicle{ - trip_id: trip_id_1, - stop_id: stop_id_1, - status: :incoming - }, - {trip_id_2, stop_id_1} => %Vehicles.Vehicle{ - trip_id: trip_id_2, - stop_id: stop_id_1, - status: :stopped - } - } - - prediction = build(:prediction, %{stop: %Stops.Stop{id: stop_id_1}}) - - Predictions.Repo.Mock - |> expect(:all, fn arg -> - assert arg[:route] == route_id - [] - end) - |> expect(:all, fn arg -> - assert arg[:trip] == Enum.join(Enum.sort([trip_id_1, trip_id_2]), ",") - # we transform the data into this form so that we only need to make one repo call - [ - prediction - ] - end) - - conn = - conn - |> assign(:origin, %Stops.Stop{id: Faker.Pokemon.location()}) - |> assign(:destination, %Stops.Stop{id: Faker.Pokemon.location()}) - |> assign(:route, %{id: route_id}) - |> assign(:direction_id, Faker.Util.pick([0, 1])) - |> assign(:vehicle_locations, vehicle_locations) - |> all_predictions() - - assert conn.assigns.vehicle_predictions == [ - prediction - ] - end - - test "assigns empty lists if the predictions return an error", %{conn: conn} do - route_id = "#{Faker.Util.digit()}" - - expect(Predictions.Repo.Mock, :all, fn [route: ^route_id] -> - {:error, :no_predictions} - end) - - conn = all_predictions(conn) - - assert conn.assigns.predictions == [] - assert conn.assigns.vehicle_predictions == [] - end - end -end